<!doctype html>
<!--
@license
Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
Code distributed by Google as part of the polymer project is also
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
-->
<html>
<head>
  <meta charset="utf-8">
  <script src="../../../webcomponentsjs/webcomponents-lite.js"></script>
  <script src="../../../web-component-tester/browser.js"></script>
  <link rel="import" href="../../polymer.html">
  <link rel="import" href="dom-repeat-elements.html">
</head>
<body>

  <h4>x-simple-repeat</h4>
  <x-simple-repeat id="simple"></x-simple-repeat>

  <h4>x-primitive-repeat</h4>
  <x-primitive-repeat id="primitive"></x-primitive-repeat>

  <h4>x-nested-repeat-configured</h4>
  <x-nested-repeat-configured id="configured"></x-nested-repeat-configured>

  <template is="dom-bind" id="unconfigured">
    <h4>x-nested-repeat unconfigured1</h4>
    <x-nested-repeat id="unconfigured1" items="{{items}}"></x-nested-repeat>
    <h4>x-nested-repeat unconfigured2</h4>
    <x-nested-repeat id="unconfigured2" items="{{items}}"></x-nested-repeat>
  </template>

  <h4>inDocumentRepeater</h4>
  <div id="inDocumentContainerOrig">
    <template id="inDocumentRepeater" is="dom-repeat" as="itema" index-as="indexa">
      <x-foo
             innera-prop="{{innera.prop}}"
             itema-prop="{{itema.prop}}"
             indexa="{{indexa}}">
      </x-foo>
      <template is="dom-repeat" items="{{itema.items}}" as="itemb" index-as="indexb">
        <x-foo
               innerb-prop="{{innerb.prop}}"
               itemb-prop="{{itemb.prop}}"
               innera-prop="{{innera.prop}}"
               itema-prop="{{itema.prop}}"
               indexa="{{indexa}}"
               indexb="{{indexb}}">
        </x-foo>
        <template is="dom-repeat" items="{{itemb.items}}" as="itemc" index-as="indexc">
          <x-foo
                 innerc-prop="{{innerc.prop}}"
                 itemc-prop="{{itemc.prop}}"
                 innerb-prop="{{innerb.prop}}"
                 itemb-prop="{{itemb.prop}}"
                 innera-prop="{{innera.prop}}"
                 itema-prop="{{itema.prop}}"
                 indexa="{{indexa}}"
                 indexb="{{indexb}}"
                 indexc="{{indexc}}">
          </x-foo>
        </template>
      </template>
    </template>
  </div>

  <h4>x-primitive-large</h4>
  <x-primitive-large id="primitiveLarge"></x-primitive-large>

  <h4>x-repeat-limit</h4>
  <x-repeat-limit id="limited"></x-repeat-limit>

  <h4>x-repeat-chunked</h4>
  <x-repeat-chunked id="chunked"></x-repeat-chunked>

  <div id="inDocumentContainer">
  </div>

  <script>
  /* global unconfigured1 unconfigured primitive limited inDocumentRepeater configured inDocumentContainer inDocumentContainerOrig unconfigured2 primitiveLarge simple:true model:true stamped:true chunked */

    /*
      Expected:

      stamped[0] ... 1
      stamped[1] ... 1-1
      stamped[2] ... 1-1-1
      stamped[3] ... 1-1-2
      stamped[4] ... 1-1-3
      stamped[5] ... 1-2
      ...
      stamped[13] .. 2
      ...
      stamped[36] .. 3-3-1
      stamped[37] .. 3-3-2
      stamped[38] .. 3-3-3
    */


    suite('errors', function() {

      test('items must be array', function() {
        var warned = false;
        inDocumentRepeater._error = function(message) {
          assert.match(message, /expected array/);
          warned = true;
        };
        inDocumentRepeater.items = {};
        assert.equal(warned, true, 'should warn when items is not array');
      });

    });

    suite('nested pre-configured dom-repeat', function() {

      test('basic rendering, downward item binding', function() {
        var stamped = Polymer.dom(configured.root).querySelectorAll('*:not(template)');
        assert.equal(stamped.length, 3 + 3*3 + 3*3*3, 'total stamped count incorrect');
        assert.equal(configured.$.repeater.renderedItemCount, 3, 'rendered item count incorrect');
        assert.equal(stamped[0].itemaProp, 'prop-1');
        assert.equal(stamped[0].computeda, 'prop-1+itemForComputedA');
        assert.equal(stamped[0].indexa, 0);
        assert.equal(stamped[0].$.bar.itemaProp, 'prop-1');
        assert.equal(stamped[1].itembProp, 'prop-1-1');
        assert.equal(stamped[1].computedb, 'prop-1-1+itemForComputedB');
        assert.equal(stamped[1].indexa, 0);
        assert.equal(stamped[1].indexb, 0);
        assert.equal(stamped[1].$.bar.itembProp, 'prop-1-1');
        assert.equal(stamped[2].itemcProp, 'prop-1-1-1');
        assert.equal(stamped[2].computedc, 'prop-1-1-1+itemForComputedC');
        assert.equal(stamped[2].indexa, 0);
        assert.equal(stamped[2].indexb, 0);
        assert.equal(stamped[2].indexc, 0);
        assert.equal(stamped[2].$.bar.itemcProp, 'prop-1-1-1');
        assert.equal(stamped[3].itemcProp, 'prop-1-1-2');
        assert.equal(stamped[3].indexa, 0);
        assert.equal(stamped[3].indexb, 0);
        assert.equal(stamped[3].indexc, 1);
        assert.equal(stamped[3].$.bar.itemcProp, 'prop-1-1-2');
        assert.equal(stamped[4].itemcProp, 'prop-1-1-3');
        assert.equal(stamped[4].indexa, 0);
        assert.equal(stamped[4].indexb, 0);
        assert.equal(stamped[4].indexc, 2);
        assert.equal(stamped[4].$.bar.itemcProp, 'prop-1-1-3');
        assert.equal(stamped[13].itemaProp, 'prop-2');
        assert.equal(stamped[13].indexa, 1);
        assert.equal(stamped[13].$.bar.itemaProp, 'prop-2');
        assert.equal(stamped[36].itemcProp, 'prop-3-3-1');
        assert.equal(stamped[36].indexa, 2);
        assert.equal(stamped[36].indexb, 2);
        assert.equal(stamped[36].indexc, 0);
        assert.equal(stamped[36].$.bar.itemcProp, 'prop-3-3-1');
        assert.equal(stamped[37].itemcProp, 'prop-3-3-2');
        assert.equal(stamped[37].indexa, 2);
        assert.equal(stamped[37].indexb, 2);
        assert.equal(stamped[37].indexc, 1);
        assert.equal(stamped[37].$.bar.itemcProp, 'prop-3-3-2');
        assert.equal(stamped[38].itemcProp, 'prop-3-3-3');
        assert.equal(stamped[38].indexa, 2);
        assert.equal(stamped[38].indexb, 2);
        assert.equal(stamped[38].indexc, 2);
        assert.equal(stamped[38].$.bar.itemcProp, 'prop-3-3-3');
      });

      test('parent scope binding', function() {
        var stamped = Polymer.dom(configured.root).querySelectorAll('*:not(template)');
        assert.equal(stamped[0].outerProp, 'outer');
        assert.equal(stamped[0].outerItemProp, 'outerItem');
        assert.equal(stamped[1].itemaProp, 'prop-1');
        assert.equal(stamped[1].indexa, 0);
        assert.equal(stamped[1].outerProp, 'outer');
        assert.equal(stamped[1].outerItemProp, 'outerItem');
        assert.equal(stamped[2].itembProp, 'prop-1-1');
        assert.equal(stamped[2].indexa, 0);
        assert.equal(stamped[2].indexb, 0);
        assert.equal(stamped[2].itemaProp, 'prop-1');
        assert.equal(stamped[2].indexa, 0);
        assert.equal(stamped[2].outerProp, 'outer');
        assert.equal(stamped[2].outerItemProp, 'outerItem');
        assert.equal(stamped[38].itembProp, 'prop-3-3');
        assert.equal(stamped[38].indexa, 2);
        assert.equal(stamped[38].indexb, 2);
        assert.equal(stamped[38].itemaProp, 'prop-3');
        assert.equal(stamped[38].indexa, 2);
        assert.equal(stamped[38].outerProp, 'outer');
        assert.equal(stamped[38].outerItemProp, 'outerItem');
      });

      test('parent scope downward notification', function() {
        var stamped = Polymer.dom(configured.root).querySelectorAll('*:not(template)');
        configured.prop = 'yes';
        assert.equal(stamped[0].outerProp, 'yes');
        assert.equal(stamped[1].outerProp, 'yes');
        assert.equal(stamped[2].outerProp, 'yes');
        assert.equal(stamped[38].outerProp, 'yes');
        configured.set('item.prop', 'yay');
        assert.equal(stamped[0].outerItemProp, 'yay');
        assert.equal(stamped[1].outerItemProp, 'yay');
        assert.equal(stamped[2].outerItemProp, 'yay');
        assert.equal(stamped[38].outerItemProp, 'yay');
      });

      test('parent upward upward notification', function() {
        var stamped = Polymer.dom(configured.root).querySelectorAll('*:not(template)');
        stamped[38].outerProp = 'nice';
        assert.equal(configured.prop, 'nice');
        assert.equal(stamped[0].outerProp, 'nice');
        assert.equal(stamped[1].outerProp, 'nice');
        assert.equal(stamped[2].outerProp, 'nice');
        assert.equal(stamped[37].outerProp, 'nice');
        stamped[38].outerItemProp = 'cool';
        assert.equal(configured.item.prop, 'cool');
        assert.equal(stamped[0].outerItemProp, 'cool');
        assert.equal(stamped[1].outerItemProp, 'cool');
        assert.equal(stamped[2].outerItemProp, 'cool');
        assert.equal(stamped[37].outerItemProp, 'cool');
      });

      // Anonymous inner scope feature removed for time being
      // test('anonymous scope binding', function() {
      //   var stamped = Polymer.dom(configured.root).querySelectorAll('*:not(template)');
      //   stamped[1].$.bar.inneraProp = 'changed';
      //   assert.equal(stamped[1].inneraProp, 'changed');
      //   assert.equal(stamped[2].inneraProp, 'changed');
      //   assert.equal(stamped[3].inneraProp, 'changed');
      //   assert.equal(stamped[4].inneraProp, 'changed');
      // });

      test('sort function by name on host', function() {
        // set sort fn
        configured.$.repeater.sort = 'sortDesc';
        configured.$.repeater.render();
        var stamped = Polymer.dom(configured.root).querySelectorAll('*:not(template)');
        assert.equal(stamped.length, 3 + 3*3 + 3*3*3, 'total stamped count incorrect');
        assert.equal(stamped[0].itemaProp, 'prop-3');
        assert.equal(stamped[0].indexa, 0);
        assert.equal(stamped[13].itemaProp, 'prop-2');
        assert.equal(stamped[13].indexa, 1);
        assert.equal(stamped[26].itemaProp, 'prop-1');
        assert.equal(stamped[26].indexa, 2);
        // reset sort fn
        configured.$.repeater.sort = null;
        configured.$.repeater.render();
        assert.equal(stamped.length, 3 + 3*3 + 3*3*3, 'total stamped count incorrect');
        assert.equal(stamped[0].itemaProp, 'prop-1');
        assert.equal(stamped[0].indexa, 0);
        assert.equal(stamped[13].itemaProp, 'prop-2');
        assert.equal(stamped[13].indexa, 1);
        assert.equal(stamped[26].itemaProp, 'prop-3');
        assert.equal(stamped[26].indexa, 2);
      });

      test('sort function imperative', function() {
        // set sort fn
        configured.$.repeater.sort = function(a, b) {
          return b.prop.localeCompare(a.prop);
        };
        configured.$.repeater.render();
        var stamped = Polymer.dom(configured.root).querySelectorAll('*:not(template)');
        assert.equal(stamped.length, 3 + 3*3 + 3*3*3, 'total stamped count incorrect');
        assert.equal(stamped[0].itemaProp, 'prop-3');
        assert.equal(stamped[0].indexa, 0);
        assert.equal(stamped[13].itemaProp, 'prop-2');
        assert.equal(stamped[13].indexa, 1);
        assert.equal(stamped[26].itemaProp, 'prop-1');
        assert.equal(stamped[26].indexa, 2);
        // reset sort fn
        configured.$.repeater.sort = null;
        configured.$.repeater.render();
        assert.equal(stamped.length, 3 + 3*3 + 3*3*3, 'total stamped count incorrect');
        assert.equal(stamped[0].itemaProp, 'prop-1');
        assert.equal(stamped[0].indexa, 0);
        assert.equal(stamped[13].itemaProp, 'prop-2');
        assert.equal(stamped[13].indexa, 1);
        assert.equal(stamped[26].itemaProp, 'prop-3');
        assert.equal(stamped[26].indexa, 2);
      });

      test('filter function by name on host', function() {
        // set filter fn
        configured.$.repeater.filter = 'filter2nd';
        configured.$.repeater.render();
        CustomElements.takeRecords();
        CustomElements.takeRecords();
        var stamped = Polymer.dom(configured.root).querySelectorAll('*:not(template)');
        assert.equal(stamped.length, 2 + 2*3 + 2*3*3, 'total stamped count incorrect');
        assert.equal(configured.$.repeater.renderedItemCount, 2, 'rendered item count incorrect');
        assert.equal(stamped[0].itemaProp, 'prop-1');
        assert.equal(stamped[0].indexa, 0);
        assert.equal(stamped[13].itemaProp, 'prop-3');
        assert.equal(stamped[13].indexa, 1);
        // reset filter fn
        configured.$.repeater.filter = null;
        configured.$.repeater.render();
        CustomElements.takeRecords();
        stamped = Polymer.dom(configured.root).querySelectorAll('*:not(template)');
        assert.equal(stamped.length, 3 + 3*3 + 3*3*3, 'total stamped count incorrect');
        assert.equal(stamped[0].itemaProp, 'prop-1');
        assert.equal(stamped[0].indexa, 0);
        assert.equal(stamped[13].itemaProp, 'prop-2');
        assert.equal(stamped[13].indexa, 1);
        assert.equal(stamped[26].itemaProp, 'prop-3');
        assert.equal(stamped[26].indexa, 2);
      });

      test('filter function imperative', function() {
        // set filter fn
        configured.$.repeater.filter = function(o) {
          return o.prop.indexOf('2') < 0;
        };
        configured.$.repeater.render();
        CustomElements.takeRecords();
        CustomElements.takeRecords();
        var stamped = Polymer.dom(configured.root).querySelectorAll('*:not(template)');
        assert.equal(stamped.length, 2 + 2*3 + 2*3*3, 'total stamped count incorrect');
        assert.equal(stamped[0].itemaProp, 'prop-1');
        assert.equal(stamped[0].indexa, 0);
        assert.equal(stamped[13].itemaProp, 'prop-3');
        assert.equal(stamped[13].indexa, 1);
        // reset filter fn
        configured.$.repeater.filter = null;
        configured.$.repeater.render();
        CustomElements.takeRecords();
        stamped = Polymer.dom(configured.root).querySelectorAll('*:not(template)');
        assert.equal(stamped.length, 3 + 3*3 + 3*3*3, 'total stamped count incorrect');
        assert.equal(stamped[0].itemaProp, 'prop-1');
        assert.equal(stamped[0].indexa, 0);
        assert.equal(stamped[13].itemaProp, 'prop-2');
        assert.equal(stamped[13].indexa, 1);
        assert.equal(stamped[26].itemaProp, 'prop-3');
        assert.equal(stamped[26].indexa, 2);
      });

      test('sort and filter function by name on host', function() {
        // set filter fn
        configured.$.repeater.sort = 'sortDesc';
        configured.$.repeater.filter = 'filter2nd';
        configured.$.repeater.render();
        CustomElements.takeRecords();
        CustomElements.takeRecords();
        var stamped = Polymer.dom(configured.root).querySelectorAll('*:not(template)');
        assert.equal(stamped.length, 2 + 2*3 + 2*3*3, 'total stamped count incorrect');
        assert.equal(stamped[0].itemaProp, 'prop-3');
        assert.equal(stamped[0].indexa, 0);
        assert.equal(stamped[13].itemaProp, 'prop-1');
        assert.equal(stamped[13].indexa, 1);
        // reset filter fn
        configured.$.repeater.sort = null;
        configured.$.repeater.filter = null;
        configured.$.repeater.render();
        CustomElements.takeRecords();
        stamped = Polymer.dom(configured.root).querySelectorAll('*:not(template)');
        assert.equal(stamped.length, 3 + 3*3 + 3*3*3, 'total stamped count incorrect');
        assert.equal(stamped[0].itemaProp, 'prop-1');
        assert.equal(stamped[0].indexa, 0);
        assert.equal(stamped[13].itemaProp, 'prop-2');
        assert.equal(stamped[13].indexa, 1);
        assert.equal(stamped[26].itemaProp, 'prop-3');
        assert.equal(stamped[26].indexa, 2);
      });

      test('observe refreshes sort and filter', function(done) {
        // set filter fn
        configured.$.repeater.sort = 'sortDesc';
        configured.$.repeater.filter = 'filter2nd';
        configured.$.repeater.render();
        CustomElements.takeRecords();
        CustomElements.takeRecords();
        var stamped = Polymer.dom(configured.root).querySelectorAll('*:not(template)');
        assert.equal(stamped.length, 2 + 2*3 + 2*3*3, 'total stamped count incorrect');
        assert.equal(stamped[0].itemaProp, 'prop-3');
        assert.equal(stamped[0].indexa, 0);
        assert.equal(stamped[13].itemaProp, 'prop-1');
        assert.equal(stamped[13].indexa, 1);

        // Update observed prop to be in filter
        configured.set(['items', 1, 'prop'], 'prop-0');
        // avoid imperative/synchronous refresh() since that forces a full refresh
        setTimeout(function() {
          stamped = Polymer.dom(configured.root).querySelectorAll('*:not(template)');
          assert.equal(stamped.length, 3 + 3*3 + 3*3*3, 'total stamped count incorrect');
          assert.equal(stamped[0].itemaProp, 'prop-3');
          assert.equal(stamped[0].indexa, 0);
          assert.equal(stamped[13].itemaProp, 'prop-1');
          assert.equal(stamped[13].indexa, 1);
          assert.equal(stamped[26].itemaProp, 'prop-0');
          assert.equal(stamped[26].indexa, 2);

          // Update observed prop back to be out of the filter
          configured.set(['items', 1, 'prop'], 'prop-2');
          setTimeout(function() {
            var stamped = Polymer.dom(configured.root).querySelectorAll('*:not(template)');
            assert.equal(stamped.length, 2 + 2*3 + 2*3*3, 'total stamped count incorrect');
            assert.equal(stamped[0].itemaProp, 'prop-3');
            assert.equal(stamped[0].indexa, 0);
            assert.equal(stamped[13].itemaProp, 'prop-1');
            assert.equal(stamped[13].indexa, 1);

            // reset filter fn
            configured.$.repeater.sort = null;
            configured.$.repeater.filter = null;
            configured.$.repeater.render();
            CustomElements.takeRecords();
            stamped = Polymer.dom(configured.root).querySelectorAll('*:not(template)');
            assert.equal(stamped.length, 3 + 3*3 + 3*3*3, 'total stamped count incorrect');
            assert.equal(stamped[0].itemaProp, 'prop-1');
            assert.equal(stamped[0].indexa, 0);
            assert.equal(stamped[13].itemaProp, 'prop-2');
            assert.equal(stamped[13].indexa, 1);
            assert.equal(stamped[26].itemaProp, 'prop-3');
            assert.equal(stamped[26].indexa, 2);

            done();
          });
        });
      });

    });

    suite('nested un-configured dom-repeat in document', function() {

      test('basic rendering, downward item binding', function() {
        inDocumentRepeater.items = window.data;
        inDocumentRepeater.render();
        var stamped = Polymer.dom(inDocumentContainerOrig).querySelectorAll('*:not(template)');
        assert.equal(stamped.length, 3 + 3*3 + 3*3*3, 'total stamped count incorrect');
        assert.equal(stamped[0].itemaProp, 'prop-1');
        assert.equal(stamped[0].indexa, 0);
        assert.equal(stamped[0].$.bar.itemaProp, 'prop-1');
        assert.equal(stamped[1].itembProp, 'prop-1-1');
        assert.equal(stamped[1].indexa, 0);
        assert.equal(stamped[1].indexb, 0);
        assert.equal(stamped[1].$.bar.itembProp, 'prop-1-1');
        assert.equal(stamped[2].itemcProp, 'prop-1-1-1');
        assert.equal(stamped[2].indexa, 0);
        assert.equal(stamped[2].indexb, 0);
        assert.equal(stamped[2].indexc, 0);
        assert.equal(stamped[2].$.bar.itemcProp, 'prop-1-1-1');
        assert.equal(stamped[3].itemcProp, 'prop-1-1-2');
        assert.equal(stamped[3].indexa, 0);
        assert.equal(stamped[3].indexb, 0);
        assert.equal(stamped[3].indexc, 1);
        assert.equal(stamped[3].$.bar.itemcProp, 'prop-1-1-2');
        assert.equal(stamped[4].itemcProp, 'prop-1-1-3');
        assert.equal(stamped[4].indexa, 0);
        assert.equal(stamped[4].indexb, 0);
        assert.equal(stamped[4].indexc, 2);
        assert.equal(stamped[4].$.bar.itemcProp, 'prop-1-1-3');
        assert.equal(stamped[13].itemaProp, 'prop-2');
        assert.equal(stamped[13].indexa, 1);
        assert.equal(stamped[13].$.bar.itemaProp, 'prop-2');
        assert.equal(stamped[36].itemcProp, 'prop-3-3-1');
        assert.equal(stamped[36].indexa, 2);
        assert.equal(stamped[36].indexb, 2);
        assert.equal(stamped[36].indexc, 0);
        assert.equal(stamped[36].$.bar.itemcProp, 'prop-3-3-1');
        assert.equal(stamped[37].itemcProp, 'prop-3-3-2');
        assert.equal(stamped[37].indexa, 2);
        assert.equal(stamped[37].indexb, 2);
        assert.equal(stamped[37].indexc, 1);
        assert.equal(stamped[37].$.bar.itemcProp, 'prop-3-3-2');
        assert.equal(stamped[38].itemcProp, 'prop-3-3-3');
        assert.equal(stamped[38].indexa, 2);
        assert.equal(stamped[38].indexb, 2);
        assert.equal(stamped[38].indexc, 2);
        assert.equal(stamped[38].$.bar.itemcProp, 'prop-3-3-3');
      });

      test('move to different container', function() {
        var repeater = inDocumentRepeater;
        Polymer.dom(inDocumentContainer).appendChild(repeater);
        CustomElements.takeRecords();
        CustomElements.takeRecords();
        CustomElements.takeRecords();
        var stamped = Polymer.dom(inDocumentContainer).querySelectorAll('*:not(template)');
        assert.equal(stamped.length, 3 + 3*3 + 3*3*3, 'total stamped count incorrect');
        assert.equal(stamped[0].itemaProp, 'prop-1');
        assert.equal(stamped[0].indexa, 0);
        assert.equal(stamped[0].$.bar.itemaProp, 'prop-1');
        assert.equal(stamped[1].itembProp, 'prop-1-1');
        assert.equal(stamped[1].indexa, 0);
        assert.equal(stamped[1].indexb, 0);
        assert.equal(stamped[1].$.bar.itembProp, 'prop-1-1');
        assert.equal(stamped[2].itemcProp, 'prop-1-1-1');
        assert.equal(stamped[2].indexa, 0);
        assert.equal(stamped[2].indexb, 0);
        assert.equal(stamped[2].indexc, 0);
        assert.equal(stamped[2].$.bar.itemcProp, 'prop-1-1-1');
        assert.equal(stamped[3].itemcProp, 'prop-1-1-2');
        assert.equal(stamped[3].indexa, 0);
        assert.equal(stamped[3].indexb, 0);
        assert.equal(stamped[3].indexc, 1);
        assert.equal(stamped[3].$.bar.itemcProp, 'prop-1-1-2');
        assert.equal(stamped[4].itemcProp, 'prop-1-1-3');
        assert.equal(stamped[4].indexa, 0);
        assert.equal(stamped[4].indexb, 0);
        assert.equal(stamped[4].indexc, 2);
        assert.equal(stamped[4].$.bar.itemcProp, 'prop-1-1-3');
        assert.equal(stamped[13].itemaProp, 'prop-2');
        assert.equal(stamped[13].indexa, 1);
        assert.equal(stamped[13].$.bar.itemaProp, 'prop-2');
        assert.equal(stamped[36].itemcProp, 'prop-3-3-1');
        assert.equal(stamped[36].indexa, 2);
        assert.equal(stamped[36].indexb, 2);
        assert.equal(stamped[36].indexc, 0);
        assert.equal(stamped[36].$.bar.itemcProp, 'prop-3-3-1');
        assert.equal(stamped[37].itemcProp, 'prop-3-3-2');
        assert.equal(stamped[37].indexa, 2);
        assert.equal(stamped[37].indexb, 2);
        assert.equal(stamped[37].indexc, 1);
        assert.equal(stamped[37].$.bar.itemcProp, 'prop-3-3-2');
        assert.equal(stamped[38].itemcProp, 'prop-3-3-3');
        assert.equal(stamped[38].indexa, 2);
        assert.equal(stamped[38].indexb, 2);
        assert.equal(stamped[38].indexc, 2);
        assert.equal(stamped[38].$.bar.itemcProp, 'prop-3-3-3');
      });

      test('basic rendering, downward item binding', function() {
        var r = inDocumentRepeater;
        Polymer.dom(r.parentElement).removeChild(r);
        Polymer.dom(inDocumentContainer).appendChild(r);

        var stamped = Polymer.dom(inDocumentContainer).querySelectorAll('*:not(template)');
        assert.equal(stamped.length, 3 + 3*3 + 3*3*3, 'total stamped count incorrect');
        assert.equal(stamped[0].itemaProp, 'prop-1');
        assert.equal(stamped[0].indexa, 0);
        assert.equal(stamped[0].$.bar.itemaProp, 'prop-1');
        assert.equal(stamped[1].itembProp, 'prop-1-1');
        assert.equal(stamped[1].indexa, 0);
        assert.equal(stamped[1].indexb, 0);
        assert.equal(stamped[1].$.bar.itembProp, 'prop-1-1');
        assert.equal(stamped[2].itemcProp, 'prop-1-1-1');
        assert.equal(stamped[2].indexa, 0);
        assert.equal(stamped[2].indexb, 0);
        assert.equal(stamped[2].indexc, 0);
        assert.equal(stamped[2].$.bar.itemcProp, 'prop-1-1-1');
        assert.equal(stamped[3].itemcProp, 'prop-1-1-2');
        assert.equal(stamped[3].indexa, 0);
        assert.equal(stamped[3].indexb, 0);
        assert.equal(stamped[3].indexc, 1);
        assert.equal(stamped[3].$.bar.itemcProp, 'prop-1-1-2');
        assert.equal(stamped[4].itemcProp, 'prop-1-1-3');
        assert.equal(stamped[4].indexa, 0);
        assert.equal(stamped[4].indexb, 0);
        assert.equal(stamped[4].indexc, 2);
        assert.equal(stamped[4].$.bar.itemcProp, 'prop-1-1-3');
        assert.equal(stamped[13].itemaProp, 'prop-2');
        assert.equal(stamped[13].indexa, 1);
        assert.equal(stamped[13].$.bar.itemaProp, 'prop-2');
        assert.equal(stamped[36].itemcProp, 'prop-3-3-1');
        assert.equal(stamped[36].indexa, 2);
        assert.equal(stamped[36].indexb, 2);
        assert.equal(stamped[36].indexc, 0);
        assert.equal(stamped[36].$.bar.itemcProp, 'prop-3-3-1');
        assert.equal(stamped[37].itemcProp, 'prop-3-3-2');
        assert.equal(stamped[37].indexa, 2);
        assert.equal(stamped[37].indexb, 2);
        assert.equal(stamped[37].indexc, 1);
        assert.equal(stamped[37].$.bar.itemcProp, 'prop-3-3-2');
        assert.equal(stamped[38].itemcProp, 'prop-3-3-3');
        assert.equal(stamped[38].indexa, 2);
        assert.equal(stamped[38].indexb, 2);
        assert.equal(stamped[38].indexc, 2);
        assert.equal(stamped[38].$.bar.itemcProp, 'prop-3-3-3');
      });

      test('parent scope binding', function() {
        var stamped = Polymer.dom(inDocumentContainer).querySelectorAll('*:not(template)');
        assert.equal(stamped[1].itemaProp, 'prop-1');
        assert.equal(stamped[1].indexa, 0);
        assert.equal(stamped[2].itembProp, 'prop-1-1');
        assert.equal(stamped[2].indexa, 0);
        assert.equal(stamped[2].indexb, 0);
        assert.equal(stamped[2].itemaProp, 'prop-1');
        assert.equal(stamped[2].indexa, 0);
        assert.equal(stamped[38].itembProp, 'prop-3-3');
        assert.equal(stamped[38].indexa, 2);
        assert.equal(stamped[38].indexb, 2);
        assert.equal(stamped[38].itemaProp, 'prop-3');
        assert.equal(stamped[38].indexa, 2);
      });

      // Anonymous inner scope feature removed for time being
      // test('anonymous scope binding', function() {
      //   var stamped = Polymer.dom(inDocumentContainer).querySelectorAll('*:not(template)');
      //   stamped[1].$.bar.inneraProp = 'changed';
      //   assert.equal(stamped[1].inneraProp, 'changed');
      //   assert.equal(stamped[2].inneraProp, 'changed');
      //   assert.equal(stamped[3].inneraProp, 'changed');
      //   assert.equal(stamped[4].inneraProp, 'changed');
      // });

    });

    suite('nested un-configured dom-repeat', function() {

      test('basic rendering, downward item binding', function() {
        unconfigured.items = window.data;
        unconfigured1.$.repeater.render();
        var stamped = Polymer.dom(unconfigured1.root).querySelectorAll('*:not(template)');
        assert.equal(stamped.length, 3 + 3*3 + 3*3*3, 'total stamped count incorrect');
        assert.equal(stamped[0].itemaProp, 'prop-1');
        assert.equal(stamped[0].indexa, 0);
        assert.equal(stamped[0].$.bar.itemaProp, 'prop-1');
        assert.equal(stamped[1].itembProp, 'prop-1-1');
        assert.equal(stamped[1].indexa, 0);
        assert.equal(stamped[1].indexb, 0);
        assert.equal(stamped[1].$.bar.itembProp, 'prop-1-1');
        assert.equal(stamped[2].itemcProp, 'prop-1-1-1');
        assert.equal(stamped[2].indexa, 0);
        assert.equal(stamped[2].indexb, 0);
        assert.equal(stamped[2].indexc, 0);
        assert.equal(stamped[2].$.bar.itemcProp, 'prop-1-1-1');
        assert.equal(stamped[3].itemcProp, 'prop-1-1-2');
        assert.equal(stamped[3].indexa, 0);
        assert.equal(stamped[3].indexb, 0);
        assert.equal(stamped[3].indexc, 1);
        assert.equal(stamped[3].$.bar.itemcProp, 'prop-1-1-2');
        assert.equal(stamped[4].itemcProp, 'prop-1-1-3');
        assert.equal(stamped[4].indexa, 0);
        assert.equal(stamped[4].indexb, 0);
        assert.equal(stamped[4].indexc, 2);
        assert.equal(stamped[4].$.bar.itemcProp, 'prop-1-1-3');
        assert.equal(stamped[13].itemaProp, 'prop-2');
        assert.equal(stamped[13].indexa, 1);
        assert.equal(stamped[13].$.bar.itemaProp, 'prop-2');
        assert.equal(stamped[36].itemcProp, 'prop-3-3-1');
        assert.equal(stamped[36].indexa, 2);
        assert.equal(stamped[36].indexb, 2);
        assert.equal(stamped[36].indexc, 0);
        assert.equal(stamped[36].$.bar.itemcProp, 'prop-3-3-1');
        assert.equal(stamped[37].itemcProp, 'prop-3-3-2');
        assert.equal(stamped[37].indexa, 2);
        assert.equal(stamped[37].indexb, 2);
        assert.equal(stamped[37].indexc, 1);
        assert.equal(stamped[37].$.bar.itemcProp, 'prop-3-3-2');
        assert.equal(stamped[38].itemcProp, 'prop-3-3-3');
        assert.equal(stamped[38].indexa, 2);
        assert.equal(stamped[38].indexb, 2);
        assert.equal(stamped[38].indexc, 2);
        assert.equal(stamped[38].$.bar.itemcProp, 'prop-3-3-3');
      });

      test('parent scope binding', function() {
        var stamped = Polymer.dom(unconfigured1.root).querySelectorAll('*:not(template)');
        unconfigured1.prop = 'outer';
        unconfigured1.item = {prop: 'outerItem'};
        assert.equal(stamped[0].outerProp, 'outer');
        assert.equal(stamped[0].outerItemProp, 'outerItem');
        assert.equal(stamped[1].itemaProp, 'prop-1');
        assert.equal(stamped[1].indexa, 0);
        assert.equal(stamped[1].outerProp, 'outer');
        assert.equal(stamped[1].outerItemProp, 'outerItem');
        assert.equal(stamped[2].itembProp, 'prop-1-1');
        assert.equal(stamped[2].indexa, 0);
        assert.equal(stamped[2].indexb, 0);
        assert.equal(stamped[2].itemaProp, 'prop-1');
        assert.equal(stamped[2].indexa, 0);
        assert.equal(stamped[2].outerProp, 'outer');
        assert.equal(stamped[2].outerItemProp, 'outerItem');
        assert.equal(stamped[38].itembProp, 'prop-3-3');
        assert.equal(stamped[38].indexa, 2);
        assert.equal(stamped[38].indexb, 2);
        assert.equal(stamped[38].itemaProp, 'prop-3');
        assert.equal(stamped[38].indexa, 2);
        assert.equal(stamped[38].outerProp, 'outer');
        assert.equal(stamped[38].outerItemProp, 'outerItem');
      });

      test('parent scope downward notification', function() {
        var stamped = Polymer.dom(unconfigured1.root).querySelectorAll('*:not(template)');
        unconfigured1.prop = 'yes';
        assert.equal(stamped[0].outerProp, 'yes');
        assert.equal(stamped[1].outerProp, 'yes');
        assert.equal(stamped[2].outerProp, 'yes');
        assert.equal(stamped[38].outerProp, 'yes');
        unconfigured1.set('item.prop', 'yay');
        assert.equal(stamped[0].outerItemProp, 'yay');
        assert.equal(stamped[1].outerItemProp, 'yay');
        assert.equal(stamped[2].outerItemProp, 'yay');
        assert.equal(stamped[38].outerItemProp, 'yay');
      });

      test('parent upward upward notification', function() {
        var stamped = Polymer.dom(unconfigured1.root).querySelectorAll('*:not(template)');
        stamped[38].outerProp = 'nice';
        assert.equal(unconfigured1.prop, 'nice');
        assert.equal(stamped[0].outerProp, 'nice');
        assert.equal(stamped[1].outerProp, 'nice');
        assert.equal(stamped[2].outerProp, 'nice');
        assert.equal(stamped[37].outerProp, 'nice');
        stamped[38].outerItemProp = 'cool';
        assert.equal(unconfigured1.item.prop, 'cool');
        assert.equal(stamped[0].outerItemProp, 'cool');
        assert.equal(stamped[1].outerItemProp, 'cool');
        assert.equal(stamped[2].outerItemProp, 'cool');
        assert.equal(stamped[37].outerItemProp, 'cool');
      });

      // Anonymous inner scope feature removed for time being
      // test('anonymous scope binding', function() {
      //   var stamped = Polymer.dom(unconfigured1.root).querySelectorAll('*:not(template)');
      //   stamped[1].$.bar.inneraProp = 'changed';
      //   assert.equal(stamped[1].inneraProp, 'changed');
      //   assert.equal(stamped[2].inneraProp, 'changed');
      //   assert.equal(stamped[3].inneraProp, 'changed');
      //   assert.equal(stamped[4].inneraProp, 'changed');
      // });

      test('event handlers', function() {
        var stamped = Polymer.dom(unconfigured1.root).querySelectorAll('*:not(template)');
        stamped[0].fire('test1');
        assert.equal(unconfigured1.testHandler1Count, 1);
        stamped[1].fire('test2');
        assert.equal(unconfigured1.testHandler2Count, 1);
        stamped[2].fire('test3');
        assert.equal(unconfigured1.testHandler3Count, 1);
      });

    });

    suite('array notification between two dom-repeats', function() {

      test('change to item from one dom-repeat to other', function() {
        var stamped1 = Polymer.dom(unconfigured1.root).querySelectorAll('*:not(template)');
        var stamped2 = Polymer.dom(unconfigured2.root).querySelectorAll('*:not(template)');

        assert.equal(stamped1[0].itemaProp, 'prop-1');
        assert.equal(stamped1[0].indexa, 0);
        assert.equal(stamped2[0].itemaProp, 'prop-1');
        assert.equal(stamped2[0].indexa, 0);
        stamped1[0].$.bar.itemaProp = 'changed';
        assert.equal(stamped2[0].itemaProp, 'changed');
        stamped2[0].$.bar.itemaProp = 'prop-1';
        assert.equal(stamped1[0].itemaProp, 'prop-1');
        assert.equal(stamped1[0].indexa, 0);

        assert.equal(stamped1[1].itembProp, 'prop-1-1');
        assert.equal(stamped1[1].indexa, 0);
        assert.equal(stamped1[1].indexb, 0);
        assert.equal(stamped2[1].itembProp, 'prop-1-1');
        assert.equal(stamped2[1].indexa, 0);
        assert.equal(stamped2[1].indexb, 0);
        stamped1[1].$.bar.itembProp = 'changed';
        assert.equal(stamped2[1].itembProp, 'changed');
        stamped2[1].$.bar.itembProp = 'prop-1-1';
        assert.equal(stamped1[1].itembProp, 'prop-1-1');
        assert.equal(stamped1[1].indexa, 0);
        assert.equal(stamped1[1].indexb, 0);

        assert.equal(stamped1[2].itemcProp, 'prop-1-1-1');
        assert.equal(stamped1[2].indexa, 0);
        assert.equal(stamped1[2].indexb, 0);
        assert.equal(stamped1[2].indexc, 0);
        assert.equal(stamped2[2].itemcProp, 'prop-1-1-1');
        assert.equal(stamped2[2].indexa, 0);
        assert.equal(stamped2[2].indexb, 0);
        assert.equal(stamped2[2].indexc, 0);
        stamped1[2].$.bar.itemcProp = 'changed';
        assert.equal(stamped2[2].itemcProp, 'changed');
        stamped2[2].$.bar.itemcProp = 'prop-1-1-1';
        assert.equal(stamped1[2].itemcProp, 'prop-1-1-1');
        assert.equal(stamped1[2].indexa, 0);
        assert.equal(stamped1[2].indexb, 0);
        assert.equal(stamped1[2].indexc, 0);

        assert.equal(stamped1[38].itemcProp, 'prop-3-3-3');
        assert.equal(stamped1[38].indexa, 2);
        assert.equal(stamped1[38].indexb, 2);
        assert.equal(stamped1[38].indexc, 2);
        assert.equal(stamped2[38].itemcProp, 'prop-3-3-3');
        assert.equal(stamped2[38].indexa, 2);
        assert.equal(stamped2[38].indexb, 2);
        assert.equal(stamped2[38].indexc, 2);
        stamped1[38].$.bar.itemcProp = 'changed';
        assert.equal(stamped2[38].itemcProp, 'changed');
        stamped2[38].$.bar.itemcProp = 'prop-3-3-3';
        assert.equal(stamped1[38].itemcProp, 'prop-3-3-3');
        assert.equal(stamped1[38].indexa, 2);
        assert.equal(stamped1[38].indexb, 2);
        assert.equal(stamped1[38].indexc, 2);
      });

      test('change to non-item scope doesn\'t affect other dom-repeat', function() {
        var stamped1 = Polymer.dom(unconfigured1.root).querySelectorAll('*:not(template)');
        var stamped2 = Polymer.dom(unconfigured2.root).querySelectorAll('*:not(template)');

        unconfigured1.prop = 'foo';
        unconfigured2.prop = 'bar';
        assert.equal(stamped1[0].outerProp, 'foo');
        assert.equal(stamped1[1].outerProp, 'foo');
        assert.equal(stamped1[2].outerProp, 'foo');
        assert.equal(stamped2[0].outerProp, 'bar');
        assert.equal(stamped2[1].outerProp, 'bar');
        assert.equal(stamped2[2].outerProp, 'bar');

        stamped1[1].$.bar.inneraProp = 'bar';
      });

    });

    suite('reacting to changes, array sort', function() {

      var removed;

      test('push', function(done) {
        unconfigured1.domUpdateHandlerCount = 0;
        unconfigured.push('items', {prop: 'new-1'}, {prop: 'new-2'});
        setTimeout(function() {
          var stamped1 = Polymer.dom(unconfigured1.root).querySelectorAll('*:not(template)');
          var stamped2 = Polymer.dom(unconfigured1.root).querySelectorAll('*:not(template)');
          assert.equal(stamped1.length, 2 + 3 + 3*3 + 3*3*3, 'total stamped count incorrect');
          assert.equal(stamped2.length, 2 + 3 + 3*3 + 3*3*3, 'total stamped count incorrect');
          assert.equal(stamped1[38].itemcProp, 'prop-3-3-3');
          assert.equal(stamped1[38].indexa, 2);
          assert.equal(stamped1[38].indexb, 2);
          assert.equal(stamped1[38].indexc, 2);
          assert.equal(stamped1[39].itemaProp, 'new-1');
          assert.equal(stamped1[40].itemaProp, 'new-2');
          assert.equal(stamped1[41], undefined);
          assert.equal(stamped2[38].itemcProp, 'prop-3-3-3');
          assert.equal(stamped2[38].indexa, 2);
          assert.equal(stamped2[38].indexb, 2);
          assert.equal(stamped2[38].indexc, 2);
          assert.equal(stamped2[39].itemaProp, 'new-1');
          assert.equal(stamped2[40].itemaProp, 'new-2');
          assert.equal(stamped2[41], undefined);
          assert.equal(unconfigured1.domUpdateHandlerCount, 
            Polymer.Settings.suppressTemplateNotifications ? 0 : 1);
          done();
        });
      });

      test('undo: push (using splice)', function(done) {
        unconfigured1.domUpdateHandlerCount = 0;
        unconfigured.splice('items', 3, 2);
        setTimeout(function() {
          var stamped1 = Polymer.dom(unconfigured1.root).querySelectorAll('*:not(template)');
          var stamped2 = Polymer.dom(unconfigured1.root).querySelectorAll('*:not(template)');
          assert.equal(stamped1.length, 3 + 3*3 + 3*3*3, 'total stamped count incorrect');
          assert.equal(stamped2.length, 3 + 3*3 + 3*3*3, 'total stamped count incorrect');
          assert.equal(stamped1[38].itemcProp, 'prop-3-3-3');
          assert.equal(stamped1[38].indexa, 2);
          assert.equal(stamped1[38].indexb, 2);
          assert.equal(stamped1[38].indexc, 2);
          assert.equal(stamped1[39], undefined);
          assert.equal(stamped2[38].itemcProp, 'prop-3-3-3');
          assert.equal(stamped2[38].indexa, 2);
          assert.equal(stamped2[38].indexb, 2);
          assert.equal(stamped2[38].indexc, 2);
          assert.equal(stamped2[39], undefined);
          assert.equal(unconfigured1.domUpdateHandlerCount, 
            Polymer.Settings.suppressTemplateNotifications ? 0 : 1);
          done();
        });
      });

      test('pop', function(done) {
        removed = unconfigured.pop('items');
        setTimeout(function() {
          var stamped1 = Polymer.dom(unconfigured1.root).querySelectorAll('*:not(template)');
          var stamped2 = Polymer.dom(unconfigured1.root).querySelectorAll('*:not(template)');
          assert.equal(stamped1.length, 2 + 2*3 + 2*3*3, 'total stamped count incorrect');
          assert.equal(stamped2.length, 2 + 2*3 + 2*3*3, 'total stamped count incorrect');
          assert.equal(stamped1[25].itemcProp, 'prop-2-3-3');
          assert.equal(stamped1[25].indexa, 1);
          assert.equal(stamped1[25].indexb, 2);
          assert.equal(stamped1[25].indexc, 2);
          assert.equal(stamped1[26], undefined);
          assert.equal(stamped2[25].itemcProp, 'prop-2-3-3');
          assert.equal(stamped2[25].indexa, 1);
          assert.equal(stamped2[25].indexb, 2);
          assert.equal(stamped2[25].indexc, 2);
          assert.equal(stamped2[26], undefined);
          done();
        });
      });

      test('undo: pop (using splice)', function(done) {
        unconfigured.splice('items', 2, 0, removed);
        setTimeout(function() {
          var stamped1 = Polymer.dom(unconfigured1.root).querySelectorAll('*:not(template)');
          var stamped2 = Polymer.dom(unconfigured1.root).querySelectorAll('*:not(template)');
          assert.equal(stamped1.length, 3 + 3*3 + 3*3*3, 'total stamped count incorrect');
          assert.equal(stamped2.length, 3 + 3*3 + 3*3*3, 'total stamped count incorrect');
          assert.equal(stamped1[38].itemcProp, 'prop-3-3-3');
          assert.equal(stamped1[38].indexa, 2);
          assert.equal(stamped1[38].indexb, 2);
          assert.equal(stamped1[38].indexc, 2);
          assert.equal(stamped1[39], undefined);
          assert.equal(stamped2[38].itemcProp, 'prop-3-3-3');
          assert.equal(stamped2[38].indexa, 2);
          assert.equal(stamped2[38].indexb, 2);
          assert.equal(stamped2[38].indexc, 2);
          assert.equal(stamped2[39], undefined);
          done();
        });
      });

      test('unshift', function(done) {
        unconfigured.unshift('items', {prop: 'new-1'}, {prop: 'new-2'});
        setTimeout(function() {
          var stamped1 = Polymer.dom(unconfigured1.root).querySelectorAll('*:not(template)');
          var stamped2 = Polymer.dom(unconfigured1.root).querySelectorAll('*:not(template)');
          assert.equal(stamped1.length, 2 + 3 + 3*3 + 3*3*3, 'total stamped count incorrect');
          assert.equal(stamped2.length, 2 + 3 + 3*3 + 3*3*3, 'total stamped count incorrect');
          assert.equal(stamped1[0].itemaProp, 'new-1');
          assert.equal(stamped1[0].indexa, 0);
          assert.equal(stamped1[1].itemaProp, 'new-2');
          assert.equal(stamped1[1].indexa, 1);
          assert.equal(stamped1[2].itemaProp, 'prop-1');
          assert.equal(stamped1[2].indexa, 2);
          assert.equal(stamped2[0].itemaProp, 'new-1');
          assert.equal(stamped1[0].indexa, 0);
          assert.equal(stamped2[1].itemaProp, 'new-2');
          assert.equal(stamped1[1].indexa, 1);
          assert.equal(stamped2[2].itemaProp, 'prop-1');
          assert.equal(stamped2[2].indexa, 2);
          done();
        });
      });

      test('undo: unshift (using splice)', function(done) {
        unconfigured.splice('items', 0, 2);
        setTimeout(function() {
          var stamped1 = Polymer.dom(unconfigured1.root).querySelectorAll('*:not(template)');
          var stamped2 = Polymer.dom(unconfigured1.root).querySelectorAll('*:not(template)');
          assert.equal(stamped1.length, 3 + 3*3 + 3*3*3, 'total stamped count incorrect');
          assert.equal(stamped2.length, 3 + 3*3 + 3*3*3, 'total stamped count incorrect');
          assert.equal(stamped1[0].itemaProp, 'prop-1');
          assert.equal(stamped1[0].indexa, 0);
          assert.equal(stamped1[1].itembProp, 'prop-1-1');
          assert.equal(stamped1[1].indexa, 0);
          assert.equal(stamped1[1].indexb, 0);
          assert.equal(stamped2[0].itemaProp, 'prop-1');
          assert.equal(stamped2[0].indexa, 0);
          assert.equal(stamped2[1].itembProp, 'prop-1-1');
          assert.equal(stamped2[1].indexa, 0);
          assert.equal(stamped2[1].indexb, 0);
          done();
        });
      });

      test('shift', function(done) {
        removed = unconfigured.shift('items');
        setTimeout(function() {
          var stamped1 = Polymer.dom(unconfigured1.root).querySelectorAll('*:not(template)');
          var stamped2 = Polymer.dom(unconfigured1.root).querySelectorAll('*:not(template)');
          assert.equal(stamped1.length, 2 + 2*3 + 2*3*3, 'total stamped count incorrect');
          assert.equal(stamped2.length, 2 + 2*3 + 2*3*3, 'total stamped count incorrect');
          assert.equal(stamped1[0].itemaProp, 'prop-2');
          assert.equal(stamped1[0].indexa, 0);
          assert.equal(stamped1[1].itembProp, 'prop-2-1');
          assert.equal(stamped1[1].indexa, 0);
          assert.equal(stamped1[1].indexb, 0);
          assert.equal(stamped1[2].itemcProp, 'prop-2-1-1');
          assert.equal(stamped1[2].indexa, 0);
          assert.equal(stamped1[2].indexb, 0);
          assert.equal(stamped1[2].indexc, 0);
          assert.equal(stamped2[0].itemaProp, 'prop-2');
          assert.equal(stamped2[0].indexa, 0);
          assert.equal(stamped2[1].itembProp, 'prop-2-1');
          assert.equal(stamped2[1].indexa, 0);
          assert.equal(stamped2[1].indexb, 0);
          assert.equal(stamped2[2].itemcProp, 'prop-2-1-1');
          assert.equal(stamped2[2].indexa, 0);
          assert.equal(stamped2[2].indexb, 0);
          assert.equal(stamped2[2].indexc, 0);
          done();
        });
      });

      test('undo: shift (using splice)', function(done) {
        unconfigured.splice('items', 0, 0, removed);
        setTimeout(function() {
          var stamped1 = Polymer.dom(unconfigured1.root).querySelectorAll('*:not(template)');
          var stamped2 = Polymer.dom(unconfigured1.root).querySelectorAll('*:not(template)');
          assert.equal(stamped1.length, 3 + 3*3 + 3*3*3, 'total stamped count incorrect');
          assert.equal(stamped2.length, 3 + 3*3 + 3*3*3, 'total stamped count incorrect');
          assert.equal(stamped1[0].itemaProp, 'prop-1');
          assert.equal(stamped1[0].indexa, 0);
          assert.equal(stamped1[1].itembProp, 'prop-1-1');
          assert.equal(stamped1[1].indexa, 0);
          assert.equal(stamped1[1].indexb, 0);
          assert.equal(stamped1[2].itemcProp, 'prop-1-1-1');
          assert.equal(stamped1[2].indexa, 0);
          assert.equal(stamped1[2].indexb, 0);
          assert.equal(stamped1[2].indexc, 0);
          assert.equal(stamped2[0].itemaProp, 'prop-1');
          assert.equal(stamped2[0].indexa, 0);
          assert.equal(stamped2[1].itembProp, 'prop-1-1');
          assert.equal(stamped2[1].indexa, 0);
          assert.equal(stamped2[1].indexb, 0);
          assert.equal(stamped2[2].itemcProp, 'prop-1-1-1');
          assert.equal(stamped2[2].indexa, 0);
          assert.equal(stamped2[2].indexb, 0);
          assert.equal(stamped2[2].indexc, 0);
          done();
        });
      });

      test('splice - remove from middle', function(done) {
        removed = unconfigured.splice('items', 1, 1)[0];
        setTimeout(function() {
          var stamped1 = Polymer.dom(unconfigured1.root).querySelectorAll('*:not(template)');
          var stamped2 = Polymer.dom(unconfigured1.root).querySelectorAll('*:not(template)');
          assert.equal(stamped1.length, 2 + 2*3 + 2*3*3, 'total stamped count incorrect');
          assert.equal(stamped2.length, 2 + 2*3 + 2*3*3, 'total stamped count incorrect');
          assert.equal(stamped1[0].itemaProp, 'prop-1');
          assert.equal(stamped1[0].indexa, 0);
          assert.equal(stamped1[1].itembProp, 'prop-1-1');
          assert.equal(stamped1[1].indexa, 0);
          assert.equal(stamped1[1].indexb, 0);
          assert.equal(stamped1[2].itemcProp, 'prop-1-1-1');
          assert.equal(stamped1[2].indexa, 0);
          assert.equal(stamped1[2].indexb, 0);
          assert.equal(stamped1[2].indexc, 0);
          assert.equal(stamped1[13].itemaProp, 'prop-3');
          assert.equal(stamped1[13].indexa, 1);
          assert.equal(stamped1[14].itembProp, 'prop-3-1');
          assert.equal(stamped1[14].indexa, 1);
          assert.equal(stamped1[14].indexb, 0);
          assert.equal(stamped1[15].itemcProp, 'prop-3-1-1');
          assert.equal(stamped1[15].indexa, 1);
          assert.equal(stamped1[15].indexb, 0);
          assert.equal(stamped1[15].indexc, 0);
          assert.equal(stamped2[0].itemaProp, 'prop-1');
          assert.equal(stamped2[0].indexa, 0);
          assert.equal(stamped2[1].itembProp, 'prop-1-1');
          assert.equal(stamped2[1].indexa, 0);
          assert.equal(stamped2[1].indexb, 0);
          assert.equal(stamped2[2].itemcProp, 'prop-1-1-1');
          assert.equal(stamped2[2].indexa, 0);
          assert.equal(stamped2[2].indexb, 0);
          assert.equal(stamped2[2].indexc, 0);
          assert.equal(stamped2[13].itemaProp, 'prop-3');
          assert.equal(stamped2[13].indexa, 1);
          assert.equal(stamped2[14].itembProp, 'prop-3-1');
          assert.equal(stamped2[14].indexa, 1);
          assert.equal(stamped2[14].indexb, 0);
          assert.equal(stamped2[15].itemcProp, 'prop-3-1-1');
          assert.equal(stamped2[15].indexa, 1);
          assert.equal(stamped2[15].indexb, 0);
          assert.equal(stamped2[15].indexc, 0);
          done();
        });
      });

      test('undo: splice - remove from middle (using splice)', function(done) {
        unconfigured.splice('items', 1, 0, removed);
        setTimeout(function() {
          var stamped1 = Polymer.dom(unconfigured1.root).querySelectorAll('*:not(template)');
          var stamped2 = Polymer.dom(unconfigured1.root).querySelectorAll('*:not(template)');
          assert.equal(stamped1.length, 3 + 3*3 + 3*3*3, 'total stamped count incorrect');
          assert.equal(stamped2.length, 3 + 3*3 + 3*3*3, 'total stamped count incorrect');
          assert.equal(stamped1[0].itemaProp, 'prop-1');
          assert.equal(stamped1[0].indexa, 0);
          assert.equal(stamped1[1].itembProp, 'prop-1-1');
          assert.equal(stamped1[1].indexa, 0);
          assert.equal(stamped1[1].indexb, 0);
          assert.equal(stamped1[2].itemcProp, 'prop-1-1-1');
          assert.equal(stamped1[2].indexa, 0);
          assert.equal(stamped1[2].indexb, 0);
          assert.equal(stamped1[2].indexc, 0);
          assert.equal(stamped1[13].itemaProp, 'prop-2');
          assert.equal(stamped1[13].indexa, 1);
          assert.equal(stamped1[14].itembProp, 'prop-2-1');
          assert.equal(stamped1[14].indexa, 1);
          assert.equal(stamped1[14].indexb, 0);
          assert.equal(stamped1[15].itemcProp, 'prop-2-1-1');
          assert.equal(stamped1[15].indexa, 1);
          assert.equal(stamped1[15].indexb, 0);
          assert.equal(stamped1[15].indexc, 0);
          assert.equal(stamped2[0].itemaProp, 'prop-1');
          assert.equal(stamped2[0].indexa, 0);
          assert.equal(stamped2[1].itembProp, 'prop-1-1');
          assert.equal(stamped2[1].indexa, 0);
          assert.equal(stamped2[1].indexb, 0);
          assert.equal(stamped2[2].itemcProp, 'prop-1-1-1');
          assert.equal(stamped2[2].indexa, 0);
          assert.equal(stamped2[2].indexb, 0);
          assert.equal(stamped2[2].indexc, 0);
          assert.equal(stamped2[13].itemaProp, 'prop-2');
          assert.equal(stamped2[13].indexa, 1);
          assert.equal(stamped2[14].itembProp, 'prop-2-1');
          assert.equal(stamped2[14].indexa, 1);
          assert.equal(stamped2[14].indexb, 0);
          assert.equal(stamped2[15].itemcProp, 'prop-2-1-1');
          assert.equal(stamped2[15].indexa, 1);
          assert.equal(stamped2[15].indexb, 0);
          assert.equal(stamped2[15].indexc, 0);
          done();
        });
      });

      test('splice - add to middle', function(done) {
        unconfigured.splice('items', 1, 0, {prop: 'new-1'}, {prop: 'new-2'});
        setTimeout(function() {
          var stamped1 = Polymer.dom(unconfigured1.root).querySelectorAll('*:not(template)');
          var stamped2 = Polymer.dom(unconfigured1.root).querySelectorAll('*:not(template)');
          assert.equal(stamped1.length, 2 + 3 + 3*3 + 3*3*3, 'total stamped count incorrect');
          assert.equal(stamped2.length, 2 + 3 + 3*3 + 3*3*3, 'total stamped count incorrect');
          assert.equal(stamped1[0].itemaProp, 'prop-1');
          assert.equal(stamped1[0].indexa, 0);
          assert.equal(stamped1[1].itembProp, 'prop-1-1');
          assert.equal(stamped1[1].indexa, 0);
          assert.equal(stamped1[1].indexb, 0);
          assert.equal(stamped1[2].itemcProp, 'prop-1-1-1');
          assert.equal(stamped1[2].indexa, 0);
          assert.equal(stamped1[2].indexb, 0);
          assert.equal(stamped1[2].indexc, 0);
          assert.equal(stamped1[13].itemaProp, 'new-1');
          assert.equal(stamped1[13].indexa, 1);
          assert.equal(stamped1[14].itemaProp, 'new-2');
          assert.equal(stamped1[14].indexa, 2);
          assert.equal(stamped1[15].itemaProp, 'prop-2');
          assert.equal(stamped1[15].indexa, 3);
          assert.equal(stamped1[16].itembProp, 'prop-2-1');
          assert.equal(stamped1[16].indexa, 3);
          assert.equal(stamped1[16].indexb, 0);
          assert.equal(stamped1[17].itemcProp, 'prop-2-1-1');
          assert.equal(stamped1[17].indexa, 3);
          assert.equal(stamped1[17].indexb, 0);
          assert.equal(stamped1[17].indexc, 0);
          assert.equal(stamped2[0].itemaProp, 'prop-1');
          assert.equal(stamped2[0].indexa, 0);
          assert.equal(stamped2[1].itembProp, 'prop-1-1');
          assert.equal(stamped2[1].indexa, 0);
          assert.equal(stamped2[1].indexb, 0);
          assert.equal(stamped2[2].itemcProp, 'prop-1-1-1');
          assert.equal(stamped2[2].indexa, 0);
          assert.equal(stamped2[2].indexb, 0);
          assert.equal(stamped2[2].indexc, 0);
          assert.equal(stamped2[13].itemaProp, 'new-1');
          assert.equal(stamped2[13].indexa, 1);
          assert.equal(stamped2[14].itemaProp, 'new-2');
          assert.equal(stamped2[14].indexa, 2);
          assert.equal(stamped2[15].itemaProp, 'prop-2');
          assert.equal(stamped2[15].indexa, 3);
          assert.equal(stamped2[16].itembProp, 'prop-2-1');
          assert.equal(stamped2[16].indexa, 3);
          assert.equal(stamped2[16].indexb, 0);
          assert.equal(stamped2[17].itemcProp, 'prop-2-1-1');
          assert.equal(stamped2[17].indexa, 3);
          assert.equal(stamped2[17].indexb, 0);
          assert.equal(stamped2[17].indexc, 0);
          done();
        });
      });

      test('undo: splice - add to middle (using splice)', function(done) {
        unconfigured.splice('items', 1, 2);
        setTimeout(function() {
          var stamped1 = Polymer.dom(unconfigured1.root).querySelectorAll('*:not(template)');
          var stamped2 = Polymer.dom(unconfigured1.root).querySelectorAll('*:not(template)');
          assert.equal(stamped1.length, 3 + 3*3 + 3*3*3, 'total stamped count incorrect');
          assert.equal(stamped2.length, 3 + 3*3 + 3*3*3, 'total stamped count incorrect');
          assert.equal(stamped1[0].itemaProp, 'prop-1');
          assert.equal(stamped1[0].indexa, 0);
          assert.equal(stamped1[1].itembProp, 'prop-1-1');
          assert.equal(stamped1[1].indexa, 0);
          assert.equal(stamped1[1].indexb, 0);
          assert.equal(stamped1[2].itemcProp, 'prop-1-1-1');
          assert.equal(stamped1[2].indexa, 0);
          assert.equal(stamped1[2].indexb, 0);
          assert.equal(stamped1[2].indexc, 0);
          assert.equal(stamped1[13].itemaProp, 'prop-2');
          assert.equal(stamped1[13].indexa, 1);
          assert.equal(stamped1[14].itembProp, 'prop-2-1');
          assert.equal(stamped1[14].indexa, 1);
          assert.equal(stamped1[14].indexb, 0);
          assert.equal(stamped1[15].itemcProp, 'prop-2-1-1');
          assert.equal(stamped1[15].indexa, 1);
          assert.equal(stamped1[15].indexb, 0);
          assert.equal(stamped1[15].indexc, 0);
          assert.equal(stamped2[0].itemaProp, 'prop-1');
          assert.equal(stamped2[0].indexa, 0);
          assert.equal(stamped2[1].itembProp, 'prop-1-1');
          assert.equal(stamped2[1].indexa, 0);
          assert.equal(stamped2[1].indexb, 0);
          assert.equal(stamped2[2].itemcProp, 'prop-1-1-1');
          assert.equal(stamped2[2].indexa, 0);
          assert.equal(stamped2[2].indexb, 0);
          assert.equal(stamped2[2].indexc, 0);
          assert.equal(stamped2[13].itemaProp, 'prop-2');
          assert.equal(stamped2[13].indexa, 1);
          assert.equal(stamped2[14].itembProp, 'prop-2-1');
          assert.equal(stamped2[14].indexa, 1);
          assert.equal(stamped2[14].indexb, 0);
          assert.equal(stamped2[15].itemcProp, 'prop-2-1-1');
          assert.equal(stamped2[15].indexa, 1);
          assert.equal(stamped2[15].indexb, 0);
          assert.equal(stamped2[15].indexc, 0);
          done();
        });
      });

      test('splice - replace in middle', function(done) {
        removed = unconfigured.splice('items', 1, 2, {prop: 'new-1'}, {prop: 'new-2'});
        setTimeout(function() {
          var stamped1 = Polymer.dom(unconfigured1.root).querySelectorAll('*:not(template)');
          var stamped2 = Polymer.dom(unconfigured1.root).querySelectorAll('*:not(template)');
          assert.equal(stamped1.length, 2 + 1 + 1*3 + 1*3*3, 'total stamped count incorrect');
          assert.equal(stamped2.length, 2 + 1 + 1*3 + 1*3*3, 'total stamped count incorrect');
          assert.equal(stamped1[0].itemaProp, 'prop-1');
          assert.equal(stamped1[0].indexa, 0);
          assert.equal(stamped1[1].itembProp, 'prop-1-1');
          assert.equal(stamped1[1].indexa, 0);
          assert.equal(stamped1[1].indexb, 0);
          assert.equal(stamped1[2].itemcProp, 'prop-1-1-1');
          assert.equal(stamped1[2].indexa, 0);
          assert.equal(stamped1[2].indexb, 0);
          assert.equal(stamped1[2].indexc, 0);
          assert.equal(stamped1[13].itemaProp, 'new-1');
          assert.equal(stamped1[13].indexa, 1);
          assert.equal(stamped1[14].itemaProp, 'new-2');
          assert.equal(stamped1[14].indexa, 2);
          assert.equal(stamped1[15], undefined);
          assert.equal(stamped2[0].itemaProp, 'prop-1');
          assert.equal(stamped2[0].indexa, 0);
          assert.equal(stamped2[1].itembProp, 'prop-1-1');
          assert.equal(stamped2[1].indexa, 0);
          assert.equal(stamped2[1].indexb, 0);
          assert.equal(stamped2[2].itemcProp, 'prop-1-1-1');
          assert.equal(stamped2[2].indexa, 0);
          assert.equal(stamped2[2].indexb, 0);
          assert.equal(stamped2[2].indexc, 0);
          assert.equal(stamped2[13].itemaProp, 'new-1');
          assert.equal(stamped2[13].indexa, 1);
          assert.equal(stamped2[14].itemaProp, 'new-2');
          assert.equal(stamped2[14].indexa, 2);
          assert.equal(stamped2[15], undefined);
          done();
        });
      });

      test('undo: splice - replace in middle (using splice)', function(done) {
        unconfigured.splice('items', 1, 2, removed[0], removed[1]);
        setTimeout(function() {
          var stamped1 = Polymer.dom(unconfigured1.root).querySelectorAll('*:not(template)');
          var stamped2 = Polymer.dom(unconfigured1.root).querySelectorAll('*:not(template)');
          assert.equal(stamped1.length, 3 + 3*3 + 3*3*3, 'total stamped count incorrect');
          assert.equal(stamped2.length, 3 + 3*3 + 3*3*3, 'total stamped count incorrect');
          assert.equal(stamped1[0].itemaProp, 'prop-1');
          assert.equal(stamped1[0].indexa, 0);
          assert.equal(stamped1[1].itembProp, 'prop-1-1');
          assert.equal(stamped1[1].indexa, 0);
          assert.equal(stamped1[1].indexb, 0);
          assert.equal(stamped1[2].itemcProp, 'prop-1-1-1');
          assert.equal(stamped1[2].indexa, 0);
          assert.equal(stamped1[2].indexb, 0);
          assert.equal(stamped1[2].indexc, 0);
          assert.equal(stamped1[13].itemaProp, 'prop-2');
          assert.equal(stamped1[13].indexa, 1);
          assert.equal(stamped1[14].itembProp, 'prop-2-1');
          assert.equal(stamped1[14].indexa, 1);
          assert.equal(stamped1[14].indexb, 0);
          assert.equal(stamped1[15].itemcProp, 'prop-2-1-1');
          assert.equal(stamped1[15].indexa, 1);
          assert.equal(stamped1[15].indexb, 0);
          assert.equal(stamped1[15].indexc, 0);
          assert.equal(stamped2[0].itemaProp, 'prop-1');
          assert.equal(stamped2[0].indexa, 0);
          assert.equal(stamped2[1].itembProp, 'prop-1-1');
          assert.equal(stamped2[1].indexa, 0);
          assert.equal(stamped2[1].indexb, 0);
          assert.equal(stamped2[2].itemcProp, 'prop-1-1-1');
          assert.equal(stamped2[2].indexa, 0);
          assert.equal(stamped2[2].indexb, 0);
          assert.equal(stamped2[2].indexc, 0);
          assert.equal(stamped2[13].itemaProp, 'prop-2');
          assert.equal(stamped2[13].indexa, 1);
          assert.equal(stamped2[14].itembProp, 'prop-2-1');
          assert.equal(stamped2[14].indexa, 1);
          assert.equal(stamped2[14].indexb, 0);
          assert.equal(stamped2[15].itemcProp, 'prop-2-1-1');
          assert.equal(stamped2[15].indexa, 1);
          assert.equal(stamped2[15].indexb, 0);
          assert.equal(stamped2[15].indexc, 0);
          done();
        });
      });

      test('large splice', function(done) {
        primitiveLarge.splice('items', 0, 10);
        setTimeout(function() {
          var stamped =
            Polymer.dom(primitiveLarge.root).querySelectorAll('*:not(template)');
          assert.equal(stamped.length, 1, 'total stamped count incorrect');
          assert.equal(stamped[0].textContent, '10');
          done();
        });
      });

      test('css scoping retained when re-ordering', function(done) {
        if (!Polymer.Settings.useShadow) {
          // Confirm initial scoping
          var stamped = Polymer.dom(simple.root).querySelectorAll('*:not(template)');
          assert.equal(stamped[0].itemaProp, 'prop-1');
          assert(stamped[0].classList.contains('x-simple-repeat'), 'expected scoping');
          assert.equal(stamped.length, 3, 'total stamped count incorrect');
          var row = stamped[0];
          // Move
          removed = simple.splice('items', 0, 1);
          simple.splice('items', 1, 0, removed[0]);
          setTimeout(function() {
            stamped = Polymer.dom(simple.root).querySelectorAll('*:not(template)');
            assert.equal(stamped.length, 3, 'total stamped count incorrect');
            assert.equal(row, stamped[1]);
            assert.equal(stamped[1].itemaProp, 'prop-1');
            assert(stamped[1].classList.contains('x-simple-repeat'), 'expected scoping');
            // Revert
            removed = simple.splice('items', 1, 1);
            simple.splice('items', 0, 0, removed[0]);
            setTimeout(function() {
              stamped = Polymer.dom(simple.root).querySelectorAll('*:not(template)');
              assert.equal(stamped.length, 3, 'total stamped count incorrect');
              assert.equal(row, stamped[0]);
              assert.equal(stamped[0].itemaProp, 'prop-1');
              assert(stamped[0].classList.contains('x-simple-repeat'), 'expected scoping');
              done();
            });
          });
        } else {
          done();
        }
      });

    });

    suite('reacting to changes, array sort with filter', function() {

      var removed;

      test('push', function(done) {
        unconfigured1.$.repeater.filter = function(o) {
          return o.prop.indexOf('2') < 0;
        };
        unconfigured.push('items', {prop: 'new-1'}, {prop: 'new-2'});
        setTimeout(function() {
          var stamped1 = Polymer.dom(unconfigured1.root).querySelectorAll('*:not(template)');
          assert.equal(stamped1.length, 1 + 2 + 2*3 + 2*3*3, 'total stamped count incorrect');
          assert.equal(stamped1[0].itemaProp, 'prop-1');
          assert.equal(stamped1[0].indexa, 0);
          assert.equal(stamped1[1].itembProp, 'prop-1-1');
          assert.equal(stamped1[1].indexa, 0);
          assert.equal(stamped1[1].indexb, 0);
          assert.equal(stamped1[2].itemcProp, 'prop-1-1-1');
          assert.equal(stamped1[2].indexa, 0);
          assert.equal(stamped1[2].indexb, 0);
          assert.equal(stamped1[2].indexc, 0);
          assert.equal(stamped1[23].itemcProp, 'prop-3-3-1');
          assert.equal(stamped1[23].indexa, 1);
          assert.equal(stamped1[23].indexb, 2);
          assert.equal(stamped1[23].indexc, 0);
          assert.equal(stamped1[24].itemcProp, 'prop-3-3-2');
          assert.equal(stamped1[24].indexa, 1);
          assert.equal(stamped1[24].indexb, 2);
          assert.equal(stamped1[24].indexc, 1);
          assert.equal(stamped1[25].itemcProp, 'prop-3-3-3');
          assert.equal(stamped1[25].indexa, 1);
          assert.equal(stamped1[25].indexb, 2);
          assert.equal(stamped1[25].indexc, 2);
          assert.equal(stamped1[26].itemaProp, 'new-1');
          assert.equal(stamped1[26].indexa, 2);
          assert.equal(stamped1[27], undefined);
          done();
        });
      });

      test('undo: push (using splice)', function(done) {
        unconfigured.splice('items', 3, 2);
        setTimeout(function() {
          var stamped1 = Polymer.dom(unconfigured1.root).querySelectorAll('*:not(template)');
          assert.equal(stamped1.length, 2 + 2*3 + 2*3*3, 'total stamped count incorrect');
          assert.equal(stamped1[0].itemaProp, 'prop-1');
          assert.equal(stamped1[0].indexa, 0);
          assert.equal(stamped1[1].itembProp, 'prop-1-1');
          assert.equal(stamped1[1].indexa, 0);
          assert.equal(stamped1[1].indexb, 0);
          assert.equal(stamped1[2].itemcProp, 'prop-1-1-1');
          assert.equal(stamped1[2].indexa, 0);
          assert.equal(stamped1[2].indexb, 0);
          assert.equal(stamped1[2].indexc, 0);
          assert.equal(stamped1[23].itemcProp, 'prop-3-3-1');
          assert.equal(stamped1[23].indexa, 1);
          assert.equal(stamped1[23].indexb, 2);
          assert.equal(stamped1[23].indexc, 0);
          assert.equal(stamped1[24].itemcProp, 'prop-3-3-2');
          assert.equal(stamped1[24].indexa, 1);
          assert.equal(stamped1[24].indexb, 2);
          assert.equal(stamped1[24].indexc, 1);
          assert.equal(stamped1[25].itemcProp, 'prop-3-3-3');
          assert.equal(stamped1[25].indexa, 1);
          assert.equal(stamped1[25].indexb, 2);
          assert.equal(stamped1[25].indexc, 2);
          assert.equal(stamped1[26], undefined);
          done();
        });
      });

      test('pop', function(done) {
        removed = unconfigured.pop('items');
        setTimeout(function() {
          var stamped1 = Polymer.dom(unconfigured1.root).querySelectorAll('*:not(template)');
          assert.equal(stamped1.length, 1 + 1*3 + 1*3*3, 'total stamped count incorrect');
          assert.equal(stamped1[0].itemaProp, 'prop-1');
          assert.equal(stamped1[0].indexa, 0);
          assert.equal(stamped1[1].itembProp, 'prop-1-1');
          assert.equal(stamped1[1].indexa, 0);
          assert.equal(stamped1[1].indexb, 0);
          assert.equal(stamped1[2].itemcProp, 'prop-1-1-1');
          assert.equal(stamped1[2].indexa, 0);
          assert.equal(stamped1[2].indexb, 0);
          assert.equal(stamped1[2].indexc, 0);
          assert.equal(stamped1[10].itemcProp, 'prop-1-3-1');
          assert.equal(stamped1[10].indexa, 0);
          assert.equal(stamped1[10].indexb, 2);
          assert.equal(stamped1[10].indexc, 0);
          assert.equal(stamped1[11].itemcProp, 'prop-1-3-2');
          assert.equal(stamped1[11].indexa, 0);
          assert.equal(stamped1[11].indexb, 2);
          assert.equal(stamped1[11].indexc, 1);
          assert.equal(stamped1[12].itemcProp, 'prop-1-3-3');
          assert.equal(stamped1[12].indexa, 0);
          assert.equal(stamped1[12].indexb, 2);
          assert.equal(stamped1[12].indexc, 2);
          assert.equal(stamped1[13], undefined);
          done();
        });
      });

      test('undo: pop (using splice)', function(done) {
        unconfigured.splice('items', 2, 0, removed);
        setTimeout(function() {
          var stamped1 = Polymer.dom(unconfigured1.root).querySelectorAll('*:not(template)');
          assert.equal(stamped1.length, 2 + 2*3 + 2*3*3, 'total stamped count incorrect');
          assert.equal(stamped1[0].itemaProp, 'prop-1');
          assert.equal(stamped1[0].indexa, 0);
          assert.equal(stamped1[1].itembProp, 'prop-1-1');
          assert.equal(stamped1[1].indexa, 0);
          assert.equal(stamped1[1].indexb, 0);
          assert.equal(stamped1[2].itemcProp, 'prop-1-1-1');
          assert.equal(stamped1[2].indexa, 0);
          assert.equal(stamped1[2].indexb, 0);
          assert.equal(stamped1[2].indexc, 0);
          assert.equal(stamped1[23].itemcProp, 'prop-3-3-1');
          assert.equal(stamped1[23].indexa, 1);
          assert.equal(stamped1[23].indexb, 2);
          assert.equal(stamped1[23].indexc, 0);
          assert.equal(stamped1[24].itemcProp, 'prop-3-3-2');
          assert.equal(stamped1[24].indexa, 1);
          assert.equal(stamped1[24].indexb, 2);
          assert.equal(stamped1[24].indexc, 1);
          assert.equal(stamped1[25].itemcProp, 'prop-3-3-3');
          assert.equal(stamped1[25].indexa, 1);
          assert.equal(stamped1[25].indexb, 2);
          assert.equal(stamped1[25].indexc, 2);
          assert.equal(stamped1[26], undefined);
          done();
        });
      });

      test('unshift', function(done) {
        unconfigured.unshift('items', {prop: 'new-1'}, {prop: 'new-2'});
        setTimeout(function() {
          var stamped1 = Polymer.dom(unconfigured1.root).querySelectorAll('*:not(template)');
          assert.equal(stamped1.length, 1 + 2 + 2*3 + 2*3*3, 'total stamped count incorrect');
          assert.equal(stamped1[0].itemaProp, 'new-1');
          assert.equal(stamped1[0].indexa, 0);
          assert.equal(stamped1[1].itemaProp, 'prop-1');
          assert.equal(stamped1[1].indexa, 1);
          assert.equal(stamped1[2].itembProp, 'prop-1-1');
          assert.equal(stamped1[2].indexa, 1);
          assert.equal(stamped1[2].indexb, 0);
          assert.equal(stamped1[3].itemcProp, 'prop-1-1-1');
          assert.equal(stamped1[3].indexa, 1);
          assert.equal(stamped1[3].indexb, 0);
          assert.equal(stamped1[3].indexc, 0);
          done();
        });
      });

      test('undo: unshift (using splice)', function(done) {
        unconfigured.splice('items', 0, 2);
        setTimeout(function() {
          var stamped1 = Polymer.dom(unconfigured1.root).querySelectorAll('*:not(template)');
          assert.equal(stamped1.length, 2 + 2*3 + 2*3*3, 'total stamped count incorrect');
          assert.equal(stamped1[0].itemaProp, 'prop-1');
          assert.equal(stamped1[0].indexa, 0);
          assert.equal(stamped1[1].itembProp, 'prop-1-1');
          assert.equal(stamped1[1].indexa, 0);
          assert.equal(stamped1[1].indexb, 0);
          assert.equal(stamped1[2].itemcProp, 'prop-1-1-1');
          assert.equal(stamped1[2].indexa, 0);
          assert.equal(stamped1[2].indexb, 0);
          assert.equal(stamped1[2].indexc, 0);
          assert.equal(stamped1[23].itemcProp, 'prop-3-3-1');
          assert.equal(stamped1[23].indexa, 1);
          assert.equal(stamped1[23].indexb, 2);
          assert.equal(stamped1[23].indexc, 0);
          assert.equal(stamped1[24].itemcProp, 'prop-3-3-2');
          assert.equal(stamped1[24].indexa, 1);
          assert.equal(stamped1[24].indexb, 2);
          assert.equal(stamped1[24].indexc, 1);
          assert.equal(stamped1[25].itemcProp, 'prop-3-3-3');
          assert.equal(stamped1[25].indexa, 1);
          assert.equal(stamped1[25].indexb, 2);
          assert.equal(stamped1[25].indexc, 2);
          assert.equal(stamped1[26], undefined);
          done();
        });
      });

      test('shift', function(done) {
        removed = unconfigured.shift('items');
        setTimeout(function() {
          var stamped1 = Polymer.dom(unconfigured1.root).querySelectorAll('*:not(template)');
          assert.equal(stamped1.length, 1 + 1*3 + 1*3*3, 'total stamped count incorrect');
          assert.equal(stamped1[0].itemaProp, 'prop-3');
          assert.equal(stamped1[0].indexa, 0);
          assert.equal(stamped1[1].itembProp, 'prop-3-1');
          assert.equal(stamped1[1].indexa, 0);
          assert.equal(stamped1[1].indexb, 0);
          assert.equal(stamped1[2].itemcProp, 'prop-3-1-1');
          assert.equal(stamped1[2].indexa, 0);
          assert.equal(stamped1[2].indexb, 0);
          assert.equal(stamped1[2].indexc, 0);
          assert.equal(stamped1[10].itemcProp, 'prop-3-3-1');
          assert.equal(stamped1[10].indexa, 0);
          assert.equal(stamped1[10].indexb, 2);
          assert.equal(stamped1[10].indexc, 0);
          assert.equal(stamped1[11].itemcProp, 'prop-3-3-2');
          assert.equal(stamped1[11].indexa, 0);
          assert.equal(stamped1[11].indexb, 2);
          assert.equal(stamped1[11].indexc, 1);
          assert.equal(stamped1[12].itemcProp, 'prop-3-3-3');
          assert.equal(stamped1[12].indexa, 0);
          assert.equal(stamped1[12].indexb, 2);
          assert.equal(stamped1[12].indexc, 2);
          assert.equal(stamped1[13], undefined);
          done();
        });
      });

      test('undo: shift (using splice)', function(done) {
        unconfigured.splice('items', 0, 0, removed);
        setTimeout(function() {
          var stamped1 = Polymer.dom(unconfigured1.root).querySelectorAll('*:not(template)');
          assert.equal(stamped1.length, 2 + 2*3 + 2*3*3, 'total stamped count incorrect');
          assert.equal(stamped1[0].itemaProp, 'prop-1');
          assert.equal(stamped1[0].indexa, 0);
          assert.equal(stamped1[1].itembProp, 'prop-1-1');
          assert.equal(stamped1[1].indexa, 0);
          assert.equal(stamped1[1].indexb, 0);
          assert.equal(stamped1[2].itemcProp, 'prop-1-1-1');
          assert.equal(stamped1[2].indexa, 0);
          assert.equal(stamped1[2].indexb, 0);
          assert.equal(stamped1[2].indexc, 0);
          assert.equal(stamped1[23].itemcProp, 'prop-3-3-1');
          assert.equal(stamped1[23].indexa, 1);
          assert.equal(stamped1[23].indexb, 2);
          assert.equal(stamped1[23].indexc, 0);
          assert.equal(stamped1[24].itemcProp, 'prop-3-3-2');
          assert.equal(stamped1[24].indexa, 1);
          assert.equal(stamped1[24].indexb, 2);
          assert.equal(stamped1[24].indexc, 1);
          assert.equal(stamped1[25].itemcProp, 'prop-3-3-3');
          assert.equal(stamped1[25].indexa, 1);
          assert.equal(stamped1[25].indexb, 2);
          assert.equal(stamped1[25].indexc, 2);
          assert.equal(stamped1[26], undefined);
          done();
        });
      });

      test('splice - remove from middle', function(done) {
        removed = unconfigured.splice('items', 1, 1)[0];
        setTimeout(function() {
          var stamped1 = Polymer.dom(unconfigured1.root).querySelectorAll('*:not(template)');
          assert.equal(stamped1.length, 2 + 2*3 + 2*3*3, 'total stamped count incorrect');
          assert.equal(stamped1[0].itemaProp, 'prop-1');
          assert.equal(stamped1[0].indexa, 0);
          assert.equal(stamped1[1].itembProp, 'prop-1-1');
          assert.equal(stamped1[1].indexa, 0);
          assert.equal(stamped1[1].indexb, 0);
          assert.equal(stamped1[2].itemcProp, 'prop-1-1-1');
          assert.equal(stamped1[2].indexa, 0);
          assert.equal(stamped1[2].indexb, 0);
          assert.equal(stamped1[2].indexc, 0);
          assert.equal(stamped1[23].itemcProp, 'prop-3-3-1');
          assert.equal(stamped1[23].indexa, 1);
          assert.equal(stamped1[23].indexb, 2);
          assert.equal(stamped1[23].indexc, 0);
          assert.equal(stamped1[24].itemcProp, 'prop-3-3-2');
          assert.equal(stamped1[24].indexa, 1);
          assert.equal(stamped1[24].indexb, 2);
          assert.equal(stamped1[24].indexc, 1);
          assert.equal(stamped1[25].itemcProp, 'prop-3-3-3');
          assert.equal(stamped1[25].indexa, 1);
          assert.equal(stamped1[25].indexb, 2);
          assert.equal(stamped1[25].indexc, 2);
          assert.equal(stamped1[26], undefined);
          done();
        });
      });

      test('undo: splice - remove from middle (using splice)', function(done) {
        unconfigured.splice('items', 1, 0, removed);
        setTimeout(function() {
          var stamped1 = Polymer.dom(unconfigured1.root).querySelectorAll('*:not(template)');
          assert.equal(stamped1.length, 2 + 2*3 + 2*3*3, 'total stamped count incorrect');
          assert.equal(stamped1[0].itemaProp, 'prop-1');
          assert.equal(stamped1[0].indexa, 0);
          assert.equal(stamped1[1].itembProp, 'prop-1-1');
          assert.equal(stamped1[1].indexa, 0);
          assert.equal(stamped1[1].indexb, 0);
          assert.equal(stamped1[2].itemcProp, 'prop-1-1-1');
          assert.equal(stamped1[2].indexa, 0);
          assert.equal(stamped1[2].indexb, 0);
          assert.equal(stamped1[2].indexc, 0);
          assert.equal(stamped1[23].itemcProp, 'prop-3-3-1');
          assert.equal(stamped1[23].indexa, 1);
          assert.equal(stamped1[23].indexb, 2);
          assert.equal(stamped1[23].indexc, 0);
          assert.equal(stamped1[24].itemcProp, 'prop-3-3-2');
          assert.equal(stamped1[24].indexa, 1);
          assert.equal(stamped1[24].indexb, 2);
          assert.equal(stamped1[24].indexc, 1);
          assert.equal(stamped1[25].itemcProp, 'prop-3-3-3');
          assert.equal(stamped1[25].indexa, 1);
          assert.equal(stamped1[25].indexb, 2);
          assert.equal(stamped1[25].indexc, 2);
          assert.equal(stamped1[26], undefined);
          done();
        });
      });

      test('splice - add to middle', function(done) {
        unconfigured.splice('items', 1, 0, {prop: 'new-1'}, {prop: 'new-2'});
        setTimeout(function() {
          var stamped1 = Polymer.dom(unconfigured1.root).querySelectorAll('*:not(template)');
          assert.equal(stamped1.length, 1 + 2 + 2*3 + 2*3*3, 'total stamped count incorrect');
          assert.equal(stamped1[0].itemaProp, 'prop-1');
          assert.equal(stamped1[0].indexa, 0);
          assert.equal(stamped1[1].itembProp, 'prop-1-1');
          assert.equal(stamped1[1].indexa, 0);
          assert.equal(stamped1[1].indexb, 0);
          assert.equal(stamped1[2].itemcProp, 'prop-1-1-1');
          assert.equal(stamped1[2].indexa, 0);
          assert.equal(stamped1[2].indexb, 0);
          assert.equal(stamped1[2].indexc, 0);
          assert.equal(stamped1[13].itemaProp, 'new-1');
          assert.equal(stamped1[13].indexa, 1);
          assert.equal(stamped1[14].itemaProp, 'prop-3');
          assert.equal(stamped1[14].indexa, 2);
          assert.equal(stamped1[15].itembProp, 'prop-3-1');
          assert.equal(stamped1[15].indexa, 2);
          assert.equal(stamped1[15].indexb, 0);
          assert.equal(stamped1[16].itemcProp, 'prop-3-1-1');
          assert.equal(stamped1[16].indexa, 2);
          assert.equal(stamped1[16].indexb, 0);
          assert.equal(stamped1[16].indexc, 0);
          done();
        });
      });

      test('undo: splice - add to middle (using splice)', function(done) {
        unconfigured.splice('items', 1, 2);
        setTimeout(function() {
          var stamped1 = Polymer.dom(unconfigured1.root).querySelectorAll('*:not(template)');
          assert.equal(stamped1.length, 2 + 2*3 + 2*3*3, 'total stamped count incorrect');
          assert.equal(stamped1[0].itemaProp, 'prop-1');
          assert.equal(stamped1[0].indexa, 0);
          assert.equal(stamped1[1].itembProp, 'prop-1-1');
          assert.equal(stamped1[1].indexa, 0);
          assert.equal(stamped1[1].indexb, 0);
          assert.equal(stamped1[2].itemcProp, 'prop-1-1-1');
          assert.equal(stamped1[2].indexa, 0);
          assert.equal(stamped1[2].indexb, 0);
          assert.equal(stamped1[2].indexc, 0);
          assert.equal(stamped1[23].itemcProp, 'prop-3-3-1');
          assert.equal(stamped1[23].indexa, 1);
          assert.equal(stamped1[23].indexb, 2);
          assert.equal(stamped1[23].indexc, 0);
          assert.equal(stamped1[24].itemcProp, 'prop-3-3-2');
          assert.equal(stamped1[24].indexa, 1);
          assert.equal(stamped1[24].indexb, 2);
          assert.equal(stamped1[24].indexc, 1);
          assert.equal(stamped1[25].itemcProp, 'prop-3-3-3');
          assert.equal(stamped1[25].indexa, 1);
          assert.equal(stamped1[25].indexb, 2);
          assert.equal(stamped1[25].indexc, 2);
          assert.equal(stamped1[26], undefined);
          done();
        });
      });

      test('splice - replace in middle', function(done) {
        removed = unconfigured.splice('items', 1, 2, {prop: 'new-1'}, {prop: 'new-2'});
        setTimeout(function() {
          var stamped1 = Polymer.dom(unconfigured1.root).querySelectorAll('*:not(template)');
          assert.equal(stamped1.length, 1 + 1 + 1*3 + 1*3*3, 'total stamped count incorrect');
          assert.equal(stamped1[0].itemaProp, 'prop-1');
          assert.equal(stamped1[0].indexa, 0);
          assert.equal(stamped1[1].itembProp, 'prop-1-1');
          assert.equal(stamped1[1].indexa, 0);
          assert.equal(stamped1[1].indexb, 0);
          assert.equal(stamped1[2].itemcProp, 'prop-1-1-1');
          assert.equal(stamped1[2].indexa, 0);
          assert.equal(stamped1[2].indexb, 0);
          assert.equal(stamped1[2].indexc, 0);
          assert.equal(stamped1[13].itemaProp, 'new-1');
          assert.equal(stamped1[14], undefined);
          done();
        });
      });

      test('undo: splice - replace in middle (using splice)', function(done) {
        unconfigured.splice('items', 1, 2, removed[0], removed[1]);
        setTimeout(function() {
          var stamped1 = Polymer.dom(unconfigured1.root).querySelectorAll('*:not(template)');
          assert.equal(stamped1.length, 2 + 2*3 + 2*3*3, 'total stamped count incorrect');
          assert.equal(stamped1[0].itemaProp, 'prop-1');
          assert.equal(stamped1[0].indexa, 0);
          assert.equal(stamped1[1].itembProp, 'prop-1-1');
          assert.equal(stamped1[1].indexa, 0);
          assert.equal(stamped1[1].indexb, 0);
          assert.equal(stamped1[2].itemcProp, 'prop-1-1-1');
          assert.equal(stamped1[2].indexa, 0);
          assert.equal(stamped1[2].indexb, 0);
          assert.equal(stamped1[2].indexc, 0);
          assert.equal(stamped1[23].itemcProp, 'prop-3-3-1');
          assert.equal(stamped1[23].indexa, 1);
          assert.equal(stamped1[23].indexb, 2);
          assert.equal(stamped1[23].indexc, 0);
          assert.equal(stamped1[24].itemcProp, 'prop-3-3-2');
          assert.equal(stamped1[24].indexa, 1);
          assert.equal(stamped1[24].indexb, 2);
          assert.equal(stamped1[24].indexc, 1);
          assert.equal(stamped1[25].itemcProp, 'prop-3-3-3');
          assert.equal(stamped1[25].indexa, 1);
          assert.equal(stamped1[25].indexb, 2);
          assert.equal(stamped1[25].indexc, 2);
          assert.equal(stamped1[26], undefined);
          done();
        });
      });

    });

    suite('reacting to changes, view sort', function() {

      var removed, a, m, z;

      test('push', function(done) {
        unconfigured1.$.repeater.filter = null;
        unconfigured1.$.repeater.sort = function(a, b) {
          return b.prop == a.prop ? 0 : b.prop < a.prop ? -1 : 1;
        };
        unconfigured.push('items', a={prop: 'a'}, m={prop: 'prop-1*'}, z={prop: 'z'});
        setTimeout(function() {
          var stamped1 = Polymer.dom(unconfigured1.root).querySelectorAll('*:not(template)');
          assert.equal(stamped1.length, 3 + 3 + 3*3 + 3*3*3, 'total stamped count incorrect');
          assert.equal(stamped1[0].itemaProp, 'z');
          assert.equal(stamped1[0].indexa, 0);
          assert.equal(stamped1[1].itemaProp, 'prop-3');
          assert.equal(stamped1[1].indexa, 1);
          assert.equal(stamped1[2].itembProp, 'prop-3-1');
          assert.equal(stamped1[2].indexa, 1);
          assert.equal(stamped1[2].indexb, 0);
          assert.equal(stamped1[3].itemcProp, 'prop-3-1-1');
          assert.equal(stamped1[3].indexa, 1);
          assert.equal(stamped1[3].indexb, 0);
          assert.equal(stamped1[3].indexc, 0);
          assert.equal(stamped1[27].itemaProp, 'prop-1*');
          assert.equal(stamped1[27].indexa, 3);
          assert.equal(stamped1[40].itemcProp, 'prop-1-3-3');
          assert.equal(stamped1[40].indexa, 4);
          assert.equal(stamped1[40].indexb, 2);
          assert.equal(stamped1[40].indexc, 2);
          assert.equal(stamped1[41].itemaProp, 'a');
          assert.equal(stamped1[41].indexa, 5);
          done();
        });
      });

      test('undo: push (using arrayDelete)', function(done) {
        unconfigured.arrayDelete('items', a);
        unconfigured.arrayDelete('items', m);
        unconfigured.arrayDelete('items', z);
        setTimeout(function() {
          var stamped1 = Polymer.dom(unconfigured1.root).querySelectorAll('*:not(template)');
          assert.equal(stamped1.length, 3 + 3*3 + 3*3*3, 'total stamped count incorrect');
          assert.equal(stamped1[0].itemaProp, 'prop-3');
          assert.equal(stamped1[0].indexa, 0);
          assert.equal(stamped1[1].itembProp, 'prop-3-1');
          assert.equal(stamped1[1].indexa, 0);
          assert.equal(stamped1[1].indexb, 0);
          assert.equal(stamped1[2].itemcProp, 'prop-3-1-1');
          assert.equal(stamped1[2].indexa, 0);
          assert.equal(stamped1[2].indexb, 0);
          assert.equal(stamped1[2].indexc, 0);
          assert.equal(stamped1[36].itemcProp, 'prop-1-3-1');
          assert.equal(stamped1[36].indexa, 2);
          assert.equal(stamped1[36].indexb, 2);
          assert.equal(stamped1[36].indexc, 0);
          assert.equal(stamped1[37].itemcProp, 'prop-1-3-2');
          assert.equal(stamped1[37].indexa, 2);
          assert.equal(stamped1[37].indexb, 2);
          assert.equal(stamped1[37].indexc, 1);
          assert.equal(stamped1[38].itemcProp, 'prop-1-3-3');
          assert.equal(stamped1[38].indexa, 2);
          assert.equal(stamped1[38].indexb, 2);
          assert.equal(stamped1[38].indexc, 2);
          assert.equal(stamped1[39], undefined);
          done();
        });
      });

      test('pop', function(done) {
        removed = unconfigured.pop('items');
        setTimeout(function() {
          var stamped1 = Polymer.dom(unconfigured1.root).querySelectorAll('*:not(template)');
          assert.equal(stamped1.length, 2 + 2*3 + 2*3*3, 'total stamped count incorrect');
          assert.equal(stamped1[25].itemcProp, 'prop-1-3-3');
          assert.equal(stamped1[25].indexa, 1);
          assert.equal(stamped1[25].indexb, 2);
          assert.equal(stamped1[25].indexc, 2);
          assert.equal(stamped1[26], undefined);
          done();
        });
      });

      test('undo: pop (using splice)', function(done) {
        unconfigured.splice('items', 2, 0, removed);
        setTimeout(function() {
          var stamped1 = Polymer.dom(unconfigured1.root).querySelectorAll('*:not(template)');
          assert.equal(stamped1.length, 3 + 3*3 + 3*3*3, 'total stamped count incorrect');
          assert.equal(stamped1[0].itemaProp, 'prop-3');
          assert.equal(stamped1[0].indexa, 0);
          assert.equal(stamped1[1].itembProp, 'prop-3-1');
          assert.equal(stamped1[1].indexa, 0);
          assert.equal(stamped1[1].indexb, 0);
          assert.equal(stamped1[2].itemcProp, 'prop-3-1-1');
          assert.equal(stamped1[2].indexa, 0);
          assert.equal(stamped1[2].indexb, 0);
          assert.equal(stamped1[2].indexc, 0);
          assert.equal(stamped1[36].itemcProp, 'prop-1-3-1');
          assert.equal(stamped1[36].indexa, 2);
          assert.equal(stamped1[36].indexb, 2);
          assert.equal(stamped1[36].indexc, 0);
          assert.equal(stamped1[37].itemcProp, 'prop-1-3-2');
          assert.equal(stamped1[37].indexa, 2);
          assert.equal(stamped1[37].indexb, 2);
          assert.equal(stamped1[37].indexc, 1);
          assert.equal(stamped1[38].itemcProp, 'prop-1-3-3');
          assert.equal(stamped1[38].indexa, 2);
          assert.equal(stamped1[38].indexb, 2);
          assert.equal(stamped1[38].indexc, 2);
          assert.equal(stamped1[39], undefined);
          done();
        });
      });

      test('unshift', function(done) {
        unconfigured.unshift('items', a={prop: 'a'}, m={prop: 'prop-1*'}, z={prop: 'z'});
        setTimeout(function() {
          var stamped1 = Polymer.dom(unconfigured1.root).querySelectorAll('*:not(template)');
          assert.equal(stamped1.length, 3 + 3 + 3*3 + 3*3*3, 'total stamped count incorrect');
          assert.equal(stamped1[0].itemaProp, 'z');
          assert.equal(stamped1[0].indexa, 0);
          assert.equal(stamped1[1].itemaProp, 'prop-3');
          assert.equal(stamped1[1].indexa, 1);
          assert.equal(stamped1[2].itembProp, 'prop-3-1');
          assert.equal(stamped1[2].indexa, 1);
          assert.equal(stamped1[2].indexb, 0);
          assert.equal(stamped1[3].itemcProp, 'prop-3-1-1');
          assert.equal(stamped1[3].indexa, 1);
          assert.equal(stamped1[3].indexb, 0);
          assert.equal(stamped1[3].indexc, 0);
          assert.equal(stamped1[27].itemaProp, 'prop-1*');
          assert.equal(stamped1[27].indexa, 3);
          assert.equal(stamped1[40].itemcProp, 'prop-1-3-3');
          assert.equal(stamped1[40].indexa, 4);
          assert.equal(stamped1[40].indexb, 2);
          assert.equal(stamped1[40].indexc, 2);
          assert.equal(stamped1[41].itemaProp, 'a');
          assert.equal(stamped1[41].indexa, 5);
          done();
        });
      });

      test('undo: unshift (using arrayDelete)', function(done) {
        unconfigured.arrayDelete('items', a);
        unconfigured.arrayDelete('items', m);
        unconfigured.arrayDelete('items', z);
        setTimeout(function() {
          var stamped1 = Polymer.dom(unconfigured1.root).querySelectorAll('*:not(template)');
          assert.equal(stamped1.length, 3 + 3*3 + 3*3*3, 'total stamped count incorrect');
          assert.equal(stamped1[0].itemaProp, 'prop-3');
          assert.equal(stamped1[0].indexa, 0);
          assert.equal(stamped1[1].itembProp, 'prop-3-1');
          assert.equal(stamped1[1].indexa, 0);
          assert.equal(stamped1[1].indexb, 0);
          assert.equal(stamped1[2].itemcProp, 'prop-3-1-1');
          assert.equal(stamped1[2].indexa, 0);
          assert.equal(stamped1[2].indexb, 0);
          assert.equal(stamped1[2].indexc, 0);
          assert.equal(stamped1[36].itemcProp, 'prop-1-3-1');
          assert.equal(stamped1[36].indexa, 2);
          assert.equal(stamped1[36].indexb, 2);
          assert.equal(stamped1[36].indexc, 0);
          assert.equal(stamped1[37].itemcProp, 'prop-1-3-2');
          assert.equal(stamped1[37].indexa, 2);
          assert.equal(stamped1[37].indexb, 2);
          assert.equal(stamped1[37].indexc, 1);
          assert.equal(stamped1[38].itemcProp, 'prop-1-3-3');
          assert.equal(stamped1[38].indexa, 2);
          assert.equal(stamped1[38].indexb, 2);
          assert.equal(stamped1[38].indexc, 2);
          assert.equal(stamped1[39], undefined);
          done();
        });
      });

      test('shift', function(done) {
        removed = unconfigured.shift('items');
        setTimeout(function() {
          var stamped1 = Polymer.dom(unconfigured1.root).querySelectorAll('*:not(template)');
          assert.equal(stamped1.length, 2 + 2*3 + 2*3*3, 'total stamped count incorrect');
          assert.equal(stamped1[0].itemaProp, 'prop-3');
          assert.equal(stamped1[0].indexa, 0);
          assert.equal(stamped1[1].itembProp, 'prop-3-1');
          assert.equal(stamped1[1].indexa, 0);
          assert.equal(stamped1[1].indexb, 0);
          assert.equal(stamped1[2].itemcProp, 'prop-3-1-1');
          assert.equal(stamped1[2].indexa, 0);
          assert.equal(stamped1[2].indexb, 0);
          assert.equal(stamped1[2].indexc, 0);
          assert.equal(stamped1[23].itemcProp, 'prop-2-3-1');
          assert.equal(stamped1[23].indexa, 1);
          assert.equal(stamped1[23].indexb, 2);
          assert.equal(stamped1[23].indexc, 0);
          assert.equal(stamped1[24].itemcProp, 'prop-2-3-2');
          assert.equal(stamped1[24].indexa, 1);
          assert.equal(stamped1[24].indexb, 2);
          assert.equal(stamped1[24].indexc, 1);
          assert.equal(stamped1[25].itemcProp, 'prop-2-3-3');
          assert.equal(stamped1[25].indexa, 1);
          assert.equal(stamped1[25].indexb, 2);
          assert.equal(stamped1[25].indexc, 2);
          assert.equal(stamped1[26], undefined);
          done();
        });
      });

      test('undo: shift (using splice)', function(done) {
        unconfigured.splice('items', 0, 0, removed);
        setTimeout(function() {
          var stamped1 = Polymer.dom(unconfigured1.root).querySelectorAll('*:not(template)');
          assert.equal(stamped1.length, 3 + 3*3 + 3*3*3, 'total stamped count incorrect');
          assert.equal(stamped1[0].itemaProp, 'prop-3');
          assert.equal(stamped1[0].indexa, 0);
          assert.equal(stamped1[1].itembProp, 'prop-3-1');
          assert.equal(stamped1[1].indexa, 0);
          assert.equal(stamped1[1].indexb, 0);
          assert.equal(stamped1[2].itemcProp, 'prop-3-1-1');
          assert.equal(stamped1[2].indexa, 0);
          assert.equal(stamped1[2].indexb, 0);
          assert.equal(stamped1[2].indexc, 0);
          assert.equal(stamped1[36].itemcProp, 'prop-1-3-1');
          assert.equal(stamped1[36].indexa, 2);
          assert.equal(stamped1[36].indexb, 2);
          assert.equal(stamped1[36].indexc, 0);
          assert.equal(stamped1[37].itemcProp, 'prop-1-3-2');
          assert.equal(stamped1[37].indexa, 2);
          assert.equal(stamped1[37].indexb, 2);
          assert.equal(stamped1[37].indexc, 1);
          assert.equal(stamped1[38].itemcProp, 'prop-1-3-3');
          assert.equal(stamped1[38].indexa, 2);
          assert.equal(stamped1[38].indexb, 2);
          assert.equal(stamped1[38].indexc, 2);
          assert.equal(stamped1[39], undefined);
          done();
        });
      });

      test('splice - remove from middle', function(done) {
        removed = unconfigured.splice('items', 1, 1)[0];
        setTimeout(function() {
          var stamped1 = Polymer.dom(unconfigured1.root).querySelectorAll('*:not(template)');
          assert.equal(stamped1.length, 2 + 2*3 + 2*3*3, 'total stamped count incorrect');
          assert.equal(stamped1[0].itemaProp, 'prop-3');
          assert.equal(stamped1[0].indexa, 0);
          assert.equal(stamped1[1].itembProp, 'prop-3-1');
          assert.equal(stamped1[1].indexa, 0);
          assert.equal(stamped1[1].indexb, 0);
          assert.equal(stamped1[2].itemcProp, 'prop-3-1-1');
          assert.equal(stamped1[2].indexa, 0);
          assert.equal(stamped1[2].indexb, 0);
          assert.equal(stamped1[2].indexc, 0);
          assert.equal(stamped1[13].itemaProp, 'prop-1');
          assert.equal(stamped1[13].indexa, 1);
          assert.equal(stamped1[14].itembProp, 'prop-1-1');
          assert.equal(stamped1[14].indexa, 1);
          assert.equal(stamped1[14].indexb, 0);
          assert.equal(stamped1[15].itemcProp, 'prop-1-1-1');
          assert.equal(stamped1[15].indexa, 1);
          assert.equal(stamped1[15].indexb, 0);
          assert.equal(stamped1[15].indexc, 0);
          assert.equal(stamped1[23].itemcProp, 'prop-1-3-1');
          assert.equal(stamped1[23].indexa, 1);
          assert.equal(stamped1[23].indexb, 2);
          assert.equal(stamped1[23].indexc, 0);
          assert.equal(stamped1[24].itemcProp, 'prop-1-3-2');
          assert.equal(stamped1[24].indexa, 1);
          assert.equal(stamped1[24].indexb, 2);
          assert.equal(stamped1[24].indexc, 1);
          assert.equal(stamped1[25].itemcProp, 'prop-1-3-3');
          assert.equal(stamped1[25].indexa, 1);
          assert.equal(stamped1[25].indexb, 2);
          assert.equal(stamped1[25].indexc, 2);
          assert.equal(stamped1[26], undefined);
          done();
        });
      });

      test('undo: splice - remove from middle (using splice)', function(done) {
        unconfigured.splice('items', 1, 0, removed);
        setTimeout(function() {
          var stamped1 = Polymer.dom(unconfigured1.root).querySelectorAll('*:not(template)');
          assert.equal(stamped1.length, 3 + 3*3 + 3*3*3, 'total stamped count incorrect');
          assert.equal(stamped1[0].itemaProp, 'prop-3');
          assert.equal(stamped1[0].indexa, 0);
          assert.equal(stamped1[1].itembProp, 'prop-3-1');
          assert.equal(stamped1[1].indexa, 0);
          assert.equal(stamped1[1].indexb, 0);
          assert.equal(stamped1[2].itemcProp, 'prop-3-1-1');
          assert.equal(stamped1[2].indexa, 0);
          assert.equal(stamped1[2].indexb, 0);
          assert.equal(stamped1[2].indexc, 0);
          assert.equal(stamped1[13].itemaProp, 'prop-2');
          assert.equal(stamped1[13].indexa, 1);
          assert.equal(stamped1[14].itembProp, 'prop-2-1');
          assert.equal(stamped1[14].indexa, 1);
          assert.equal(stamped1[14].indexb, 0);
          assert.equal(stamped1[15].itemcProp, 'prop-2-1-1');
          assert.equal(stamped1[15].indexa, 1);
          assert.equal(stamped1[15].indexb, 0);
          assert.equal(stamped1[15].indexc, 0);
          assert.equal(stamped1[36].itemcProp, 'prop-1-3-1');
          assert.equal(stamped1[36].indexa, 2);
          assert.equal(stamped1[36].indexb, 2);
          assert.equal(stamped1[36].indexc, 0);
          assert.equal(stamped1[37].itemcProp, 'prop-1-3-2');
          assert.equal(stamped1[37].indexa, 2);
          assert.equal(stamped1[37].indexb, 2);
          assert.equal(stamped1[37].indexc, 1);
          assert.equal(stamped1[38].itemcProp, 'prop-1-3-3');
          assert.equal(stamped1[38].indexa, 2);
          assert.equal(stamped1[38].indexb, 2);
          assert.equal(stamped1[38].indexc, 2);
          done();
        });
      });

      test('splice - add to middle', function(done) {
        unconfigured.splice('items', 1, 0, a={prop: 'a'}, m={prop: 'prop-1*'}, z={prop: 'z'});
        setTimeout(function() {
          var stamped1 = Polymer.dom(unconfigured1.root).querySelectorAll('*:not(template)');
          assert.equal(stamped1.length, 3 + 3 + 3*3 + 3*3*3, 'total stamped count incorrect');
          assert.equal(stamped1[0].itemaProp, 'z');
          assert.equal(stamped1[0].indexa, 0);
          assert.equal(stamped1[1].itemaProp, 'prop-3');
          assert.equal(stamped1[1].indexa, 1);
          assert.equal(stamped1[2].itembProp, 'prop-3-1');
          assert.equal(stamped1[2].indexa, 1);
          assert.equal(stamped1[2].indexb, 0);
          assert.equal(stamped1[3].itemcProp, 'prop-3-1-1');
          assert.equal(stamped1[3].indexa, 1);
          assert.equal(stamped1[3].indexb, 0);
          assert.equal(stamped1[3].indexc, 0);
          assert.equal(stamped1[27].itemaProp, 'prop-1*');
          assert.equal(stamped1[27].indexa, 3);
          assert.equal(stamped1[40].itemcProp, 'prop-1-3-3');
          assert.equal(stamped1[40].indexa, 4);
          assert.equal(stamped1[40].indexb, 2);
          assert.equal(stamped1[40].indexc, 2);
          assert.equal(stamped1[41].itemaProp, 'a');
          assert.equal(stamped1[41].indexa, 5);
          done();
        });
      });

      test('undo: splice - add to middle (using arrayDelete)', function(done) {
        unconfigured.arrayDelete('items', a);
        unconfigured.arrayDelete('items', m);
        unconfigured.arrayDelete('items', z);
        setTimeout(function() {
          var stamped1 = Polymer.dom(unconfigured1.root).querySelectorAll('*:not(template)');
          assert.equal(stamped1.length, 3 + 3*3 + 3*3*3, 'total stamped count incorrect');
          assert.equal(stamped1[0].itemaProp, 'prop-3');
          assert.equal(stamped1[0].indexa, 0);
          assert.equal(stamped1[1].itembProp, 'prop-3-1');
          assert.equal(stamped1[1].indexa, 0);
          assert.equal(stamped1[1].indexb, 0);
          assert.equal(stamped1[2].itemcProp, 'prop-3-1-1');
          assert.equal(stamped1[2].indexa, 0);
          assert.equal(stamped1[2].indexb, 0);
          assert.equal(stamped1[2].indexc, 0);
          assert.equal(stamped1[36].itemcProp, 'prop-1-3-1');
          assert.equal(stamped1[36].indexa, 2);
          assert.equal(stamped1[36].indexb, 2);
          assert.equal(stamped1[36].indexc, 0);
          assert.equal(stamped1[37].itemcProp, 'prop-1-3-2');
          assert.equal(stamped1[37].indexa, 2);
          assert.equal(stamped1[37].indexb, 2);
          assert.equal(stamped1[37].indexc, 1);
          assert.equal(stamped1[38].itemcProp, 'prop-1-3-3');
          assert.equal(stamped1[38].indexa, 2);
          assert.equal(stamped1[38].indexb, 2);
          assert.equal(stamped1[38].indexc, 2);
          assert.equal(stamped1[39], undefined);
          done();
        });
      });

      test('splice - replace in middle', function(done) {
        removed = unconfigured.splice('items', 1, 2, a={prop: 'a'}, m={prop: 'prop-1*'}, z={prop: 'z'});
        setTimeout(function() {
          var stamped1 = Polymer.dom(unconfigured1.root).querySelectorAll('*:not(template)');
          assert.equal(stamped1.length, 3 + 1 + 1*3 + 1*3*3, 'total stamped count incorrect');
          assert.equal(stamped1[0].itemaProp, 'z');
          assert.equal(stamped1[0].indexa, 0);
          assert.equal(stamped1[1].itemaProp, 'prop-1*');
          assert.equal(stamped1[1].indexa, 1);
          assert.equal(stamped1[2].itemaProp, 'prop-1');
          assert.equal(stamped1[2].indexa, 2);
          assert.equal(stamped1[3].itembProp, 'prop-1-1');
          assert.equal(stamped1[3].indexa, 2);
          assert.equal(stamped1[3].indexb, 0);
          assert.equal(stamped1[4].itemcProp, 'prop-1-1-1');
          assert.equal(stamped1[4].indexa, 2);
          assert.equal(stamped1[4].indexb, 0);
          assert.equal(stamped1[4].indexc, 0);
          assert.equal(stamped1[15].itemaProp, 'a');
          assert.equal(stamped1[15].indexa, 3);
          assert.equal(stamped1[16], undefined);
          done();
        });
      });

      test('undo: splice - replace in middle (using splice)', function(done) {
        unconfigured.arrayDelete('items', a);
        unconfigured.arrayDelete('items', m);
        unconfigured.arrayDelete('items', z);
        unconfigured.splice('items', 1, 2, removed[0], removed[1]);
        setTimeout(function() {
          var stamped1 = Polymer.dom(unconfigured1.root).querySelectorAll('*:not(template)');
          assert.equal(stamped1.length, 3 + 3*3 + 3*3*3, 'total stamped count incorrect');
          assert.equal(stamped1[0].itemaProp, 'prop-3');
          assert.equal(stamped1[0].indexa, 0);
          assert.equal(stamped1[1].itembProp, 'prop-3-1');
          assert.equal(stamped1[1].indexa, 0);
          assert.equal(stamped1[1].indexb, 0);
          assert.equal(stamped1[2].itemcProp, 'prop-3-1-1');
          assert.equal(stamped1[2].indexa, 0);
          assert.equal(stamped1[2].indexb, 0);
          assert.equal(stamped1[2].indexc, 0);
          assert.equal(stamped1[36].itemcProp, 'prop-1-3-1');
          assert.equal(stamped1[36].indexa, 2);
          assert.equal(stamped1[36].indexb, 2);
          assert.equal(stamped1[36].indexc, 0);
          assert.equal(stamped1[37].itemcProp, 'prop-1-3-2');
          assert.equal(stamped1[37].indexa, 2);
          assert.equal(stamped1[37].indexb, 2);
          assert.equal(stamped1[37].indexc, 1);
          assert.equal(stamped1[38].itemcProp, 'prop-1-3-3');
          assert.equal(stamped1[38].indexa, 2);
          assert.equal(stamped1[38].indexb, 2);
          assert.equal(stamped1[38].indexc, 2);
          assert.equal(stamped1[39], undefined);
          done();
        });
      });

    });

    suite('reacting to changes, view sort with filter', function() {

      var removed, a, m, z;

      suiteSetup(function() {
        unconfigured1.$.repeater.sort = function(a, b) {
          return b.prop == a.prop ? 0 : b.prop < a.prop ? -1 : 1;
        };
        unconfigured1.$.repeater.filter = function(o) {
          return o.prop.indexOf('2') < 0;
        };
        unconfigured1.$.repeater.render();
        CustomElements.takeRecords();
        CustomElements.takeRecords();
      });

      suiteTeardown(function() {
        unconfigured1.$.repeater.sort = null;
        unconfigured1.$.repeater.filter = null;
        unconfigured1.$.repeater.render();
        CustomElements.takeRecords();
        CustomElements.takeRecords();
      });

      test('push', function(done) {
        unconfigured.push('items', a={prop: 'a'}, m={prop: 'item*2'}, z={prop: 'z'});
        setTimeout(function() {
          var stamped1 = Polymer.dom(unconfigured1.root).querySelectorAll('*:not(template)');
          assert.equal(stamped1.length, 2 + 2 + 2*3 + 2*3*3, 'total stamped count incorrect');
          assert.equal(stamped1[0].itemaProp, 'z');
          assert.equal(stamped1[0].indexa, 0);
          assert.equal(stamped1[1].itemaProp, 'prop-3');
          assert.equal(stamped1[1].indexa, 1);
          assert.equal(stamped1[2].itembProp, 'prop-3-1');
          assert.equal(stamped1[2].indexa, 1);
          assert.equal(stamped1[2].indexb, 0);
          assert.equal(stamped1[3].itemcProp, 'prop-3-1-1');
          assert.equal(stamped1[3].indexa, 1);
          assert.equal(stamped1[3].indexb, 0);
          assert.equal(stamped1[3].indexc, 0);
          assert.equal(stamped1[26].itemcProp, 'prop-1-3-3');
          assert.equal(stamped1[26].indexa, 2);
          assert.equal(stamped1[26].indexb, 2);
          assert.equal(stamped1[26].indexc, 2);
          assert.equal(stamped1[27].itemaProp, 'a');
          assert.equal(stamped1[27].indexa, 3);
          assert.equal(stamped1[28], undefined);
          done();
        });
      });

      test('undo: push (using arrayDelete)', function(done) {
        unconfigured.arrayDelete('items', a);
        unconfigured.arrayDelete('items', m);
        unconfigured.arrayDelete('items', z);
        setTimeout(function() {
          var stamped1 = Polymer.dom(unconfigured1.root).querySelectorAll('*:not(template)');
          assert.equal(stamped1.length, 2 + 2*3 + 2*3*3, 'total stamped count incorrect');
          assert.equal(stamped1[0].itemaProp, 'prop-3');
          assert.equal(stamped1[0].indexa, 0);
          assert.equal(stamped1[1].itembProp, 'prop-3-1');
          assert.equal(stamped1[1].indexa, 0);
          assert.equal(stamped1[1].indexb, 0);
          assert.equal(stamped1[2].itemcProp, 'prop-3-1-1');
          assert.equal(stamped1[2].indexa, 0);
          assert.equal(stamped1[2].indexb, 0);
          assert.equal(stamped1[2].indexc, 0);
          assert.equal(stamped1[23].itemcProp, 'prop-1-3-1');
          assert.equal(stamped1[23].indexa, 1);
          assert.equal(stamped1[23].indexb, 2);
          assert.equal(stamped1[23].indexc, 0);
          assert.equal(stamped1[24].itemcProp, 'prop-1-3-2');
          assert.equal(stamped1[24].indexa, 1);
          assert.equal(stamped1[24].indexb, 2);
          assert.equal(stamped1[24].indexc, 1);
          assert.equal(stamped1[25].itemcProp, 'prop-1-3-3');
          assert.equal(stamped1[25].indexa, 1);
          assert.equal(stamped1[25].indexb, 2);
          assert.equal(stamped1[25].indexc, 2);
          assert.equal(stamped1[26], undefined);
          done();
        });
      });

      test('pop', function(done) {
        removed = unconfigured.pop('items');
        setTimeout(function() {
          var stamped1 = Polymer.dom(unconfigured1.root).querySelectorAll('*:not(template)');
          assert.equal(stamped1.length, 1 + 1*3 + 1*3*3, 'total stamped count incorrect');
          assert.equal(stamped1[0].itemaProp, 'prop-1');
          assert.equal(stamped1[0].indexa, 0);
          assert.equal(stamped1[1].itembProp, 'prop-1-1');
          assert.equal(stamped1[1].indexa, 0);
          assert.equal(stamped1[1].indexb, 0);
          assert.equal(stamped1[2].itemcProp, 'prop-1-1-1');
          assert.equal(stamped1[2].indexa, 0);
          assert.equal(stamped1[2].indexb, 0);
          assert.equal(stamped1[2].indexc, 0);
          assert.equal(stamped1[12].itemcProp, 'prop-1-3-3');
          assert.equal(stamped1[12].indexa, 0);
          assert.equal(stamped1[12].indexb, 2);
          assert.equal(stamped1[12].indexc, 2);
          assert.equal(stamped1[13], undefined);
          done();
        });
      });

      test('undo: pop (using splice)', function(done) {
        unconfigured.splice('items', 2, 0, removed);
        setTimeout(function() {
          var stamped1 = Polymer.dom(unconfigured1.root).querySelectorAll('*:not(template)');
          assert.equal(stamped1.length, 2 + 2*3 + 2*3*3, 'total stamped count incorrect');
          assert.equal(stamped1[0].itemaProp, 'prop-3');
          assert.equal(stamped1[0].indexa, 0);
          assert.equal(stamped1[1].itembProp, 'prop-3-1');
          assert.equal(stamped1[1].indexa, 0);
          assert.equal(stamped1[1].indexb, 0);
          assert.equal(stamped1[2].itemcProp, 'prop-3-1-1');
          assert.equal(stamped1[2].indexa, 0);
          assert.equal(stamped1[2].indexb, 0);
          assert.equal(stamped1[2].indexc, 0);
          assert.equal(stamped1[23].itemcProp, 'prop-1-3-1');
          assert.equal(stamped1[23].indexa, 1);
          assert.equal(stamped1[23].indexb, 2);
          assert.equal(stamped1[23].indexc, 0);
          assert.equal(stamped1[24].itemcProp, 'prop-1-3-2');
          assert.equal(stamped1[24].indexa, 1);
          assert.equal(stamped1[24].indexb, 2);
          assert.equal(stamped1[24].indexc, 1);
          assert.equal(stamped1[25].itemcProp, 'prop-1-3-3');
          assert.equal(stamped1[25].indexa, 1);
          assert.equal(stamped1[25].indexb, 2);
          assert.equal(stamped1[25].indexc, 2);
          assert.equal(stamped1[26], undefined);
          done();
        });
      });

      test('unshift', function(done) {
        unconfigured.unshift('items', a={prop: 'a'}, m={prop: 'item*2'}, z={prop: 'z'});
        setTimeout(function() {
          var stamped1 = Polymer.dom(unconfigured1.root).querySelectorAll('*:not(template)');
          assert.equal(stamped1.length, 2 + 2 + 2*3 + 2*3*3, 'total stamped count incorrect');
          assert.equal(stamped1[0].itemaProp, 'z');
          assert.equal(stamped1[0].indexa, 0);
          assert.equal(stamped1[1].itemaProp, 'prop-3');
          assert.equal(stamped1[1].indexa, 1);
          assert.equal(stamped1[2].itembProp, 'prop-3-1');
          assert.equal(stamped1[2].indexa, 1);
          assert.equal(stamped1[2].indexb, 0);
          assert.equal(stamped1[3].itemcProp, 'prop-3-1-1');
          assert.equal(stamped1[3].indexa, 1);
          assert.equal(stamped1[3].indexb, 0);
          assert.equal(stamped1[3].indexc, 0);
          assert.equal(stamped1[26].itemcProp, 'prop-1-3-3');
          assert.equal(stamped1[26].indexa, 2);
          assert.equal(stamped1[26].indexb, 2);
          assert.equal(stamped1[26].indexc, 2);
          assert.equal(stamped1[27].itemaProp, 'a');
          assert.equal(stamped1[27].indexa, 3);
          assert.equal(stamped1[28], undefined);
          done();
        });
      });

      test('undo: unshift (using splice)', function(done) {
        unconfigured.splice('items', 0, 3);
        setTimeout(function() {
          var stamped1 = Polymer.dom(unconfigured1.root).querySelectorAll('*:not(template)');
          assert.equal(stamped1.length, 2 + 2*3 + 2*3*3, 'total stamped count incorrect');
          assert.equal(stamped1[0].itemaProp, 'prop-3');
          assert.equal(stamped1[0].indexa, 0);
          assert.equal(stamped1[1].itembProp, 'prop-3-1');
          assert.equal(stamped1[1].indexa, 0);
          assert.equal(stamped1[1].indexb, 0);
          assert.equal(stamped1[2].itemcProp, 'prop-3-1-1');
          assert.equal(stamped1[2].indexa, 0);
          assert.equal(stamped1[2].indexb, 0);
          assert.equal(stamped1[2].indexc, 0);
          assert.equal(stamped1[23].itemcProp, 'prop-1-3-1');
          assert.equal(stamped1[23].indexa, 1);
          assert.equal(stamped1[23].indexb, 2);
          assert.equal(stamped1[23].indexc, 0);
          assert.equal(stamped1[24].itemcProp, 'prop-1-3-2');
          assert.equal(stamped1[24].indexa, 1);
          assert.equal(stamped1[24].indexb, 2);
          assert.equal(stamped1[24].indexc, 1);
          assert.equal(stamped1[25].itemcProp, 'prop-1-3-3');
          assert.equal(stamped1[25].indexa, 1);
          assert.equal(stamped1[25].indexb, 2);
          assert.equal(stamped1[25].indexc, 2);
          assert.equal(stamped1[26], undefined);
          done();
        });
      });

      test('shift', function(done) {
        removed = unconfigured.shift('items');
        setTimeout(function() {
          var stamped1 = Polymer.dom(unconfigured1.root).querySelectorAll('*:not(template)');
          assert.equal(stamped1.length, 1 + 1*3 + 1*3*3, 'total stamped count incorrect');
          assert.equal(stamped1[0].itemaProp, 'prop-3');
          assert.equal(stamped1[0].indexa, 0);
          assert.equal(stamped1[1].itembProp, 'prop-3-1');
          assert.equal(stamped1[1].indexa, 0);
          assert.equal(stamped1[1].indexb, 0);
          assert.equal(stamped1[2].itemcProp, 'prop-3-1-1');
          assert.equal(stamped1[2].indexa, 0);
          assert.equal(stamped1[2].indexb, 0);
          assert.equal(stamped1[2].indexc, 0);
          assert.equal(stamped1[12].itemcProp, 'prop-3-3-3');
          assert.equal(stamped1[12].indexa, 0);
          assert.equal(stamped1[12].indexb, 2);
          assert.equal(stamped1[12].indexc, 2);
          assert.equal(stamped1[13], undefined);
          done();
        });
      });

      test('undo: shift (using splice)', function(done) {
        unconfigured.splice('items', 0, 0, removed);
        setTimeout(function() {
          var stamped1 = Polymer.dom(unconfigured1.root).querySelectorAll('*:not(template)');
          assert.equal(stamped1.length, 2 + 2*3 + 2*3*3, 'total stamped count incorrect');
          assert.equal(stamped1[0].itemaProp, 'prop-3');
          assert.equal(stamped1[0].indexa, 0);
          assert.equal(stamped1[1].itembProp, 'prop-3-1');
          assert.equal(stamped1[1].indexa, 0);
          assert.equal(stamped1[1].indexb, 0);
          assert.equal(stamped1[2].itemcProp, 'prop-3-1-1');
          assert.equal(stamped1[2].indexa, 0);
          assert.equal(stamped1[2].indexb, 0);
          assert.equal(stamped1[2].indexc, 0);
          assert.equal(stamped1[23].itemcProp, 'prop-1-3-1');
          assert.equal(stamped1[23].indexa, 1);
          assert.equal(stamped1[23].indexb, 2);
          assert.equal(stamped1[23].indexc, 0);
          assert.equal(stamped1[24].itemcProp, 'prop-1-3-2');
          assert.equal(stamped1[24].indexa, 1);
          assert.equal(stamped1[24].indexb, 2);
          assert.equal(stamped1[24].indexc, 1);
          assert.equal(stamped1[25].itemcProp, 'prop-1-3-3');
          assert.equal(stamped1[25].indexa, 1);
          assert.equal(stamped1[25].indexb, 2);
          assert.equal(stamped1[25].indexc, 2);
          assert.equal(stamped1[26], undefined);
          done();
        });
      });

      test('splice - remove from middle', function(done) {
        removed = unconfigured.splice('items', 1, 1)[0];
        setTimeout(function() {
          var stamped1 = Polymer.dom(unconfigured1.root).querySelectorAll('*:not(template)');
          assert.equal(stamped1.length, 2 + 2*3 + 2*3*3, 'total stamped count incorrect');
          assert.equal(stamped1[0].itemaProp, 'prop-3');
          assert.equal(stamped1[0].indexa, 0);
          assert.equal(stamped1[1].itembProp, 'prop-3-1');
          assert.equal(stamped1[1].indexa, 0);
          assert.equal(stamped1[1].indexb, 0);
          assert.equal(stamped1[2].itemcProp, 'prop-3-1-1');
          assert.equal(stamped1[2].indexa, 0);
          assert.equal(stamped1[2].indexb, 0);
          assert.equal(stamped1[2].indexc, 0);
          assert.equal(stamped1[13].itemaProp, 'prop-1');
          assert.equal(stamped1[13].indexa, 1);
          assert.equal(stamped1[14].itembProp, 'prop-1-1');
          assert.equal(stamped1[14].indexa, 1);
          assert.equal(stamped1[14].indexb, 0);
          assert.equal(stamped1[15].itemcProp, 'prop-1-1-1');
          assert.equal(stamped1[15].indexa, 1);
          assert.equal(stamped1[15].indexb, 0);
          assert.equal(stamped1[15].indexc, 0);
          done();
        });
      });

      test('undo: splice - remove from middle (using splice)', function(done) {
        unconfigured.splice('items', 1, 0, removed);
        setTimeout(function() {
          var stamped1 = Polymer.dom(unconfigured1.root).querySelectorAll('*:not(template)');
          assert.equal(stamped1.length, 2 + 2*3 + 2*3*3, 'total stamped count incorrect');
          assert.equal(stamped1[0].itemaProp, 'prop-3');
          assert.equal(stamped1[0].indexa, 0);
          assert.equal(stamped1[1].itembProp, 'prop-3-1');
          assert.equal(stamped1[1].indexa, 0);
          assert.equal(stamped1[1].indexb, 0);
          assert.equal(stamped1[2].itemcProp, 'prop-3-1-1');
          assert.equal(stamped1[2].indexa, 0);
          assert.equal(stamped1[2].indexb, 0);
          assert.equal(stamped1[2].indexc, 0);
          assert.equal(stamped1[23].itemcProp, 'prop-1-3-1');
          assert.equal(stamped1[23].indexa, 1);
          assert.equal(stamped1[23].indexb, 2);
          assert.equal(stamped1[23].indexc, 0);
          assert.equal(stamped1[24].itemcProp, 'prop-1-3-2');
          assert.equal(stamped1[24].indexa, 1);
          assert.equal(stamped1[24].indexb, 2);
          assert.equal(stamped1[24].indexc, 1);
          assert.equal(stamped1[25].itemcProp, 'prop-1-3-3');
          assert.equal(stamped1[25].indexa, 1);
          assert.equal(stamped1[25].indexb, 2);
          assert.equal(stamped1[25].indexc, 2);
          assert.equal(stamped1[26], undefined);
          done();
        });
      });

      test('splice - add to middle', function(done) {
        unconfigured.splice('items', 1, 0, a={prop: 'a'}, m={prop: 'item*2'}, z={prop: 'z'});
        setTimeout(function() {
          var stamped1 = Polymer.dom(unconfigured1.root).querySelectorAll('*:not(template)');
          assert.equal(stamped1.length, 2 + 2 + 2*3 + 2*3*3, 'total stamped count incorrect');
          assert.equal(stamped1[0].itemaProp, 'z');
          assert.equal(stamped1[0].indexa, 0);
          assert.equal(stamped1[1].itemaProp, 'prop-3');
          assert.equal(stamped1[1].indexa, 1);
          assert.equal(stamped1[2].itembProp, 'prop-3-1');
          assert.equal(stamped1[2].indexa, 1);
          assert.equal(stamped1[2].indexb, 0);
          assert.equal(stamped1[3].itemcProp, 'prop-3-1-1');
          assert.equal(stamped1[3].indexa, 1);
          assert.equal(stamped1[3].indexb, 0);
          assert.equal(stamped1[3].indexc, 0);
          assert.equal(stamped1[26].itemcProp, 'prop-1-3-3');
          assert.equal(stamped1[26].indexa, 2);
          assert.equal(stamped1[26].indexb, 2);
          assert.equal(stamped1[26].indexc, 2);
          assert.equal(stamped1[27].itemaProp, 'a');
          assert.equal(stamped1[27].indexa, 3);
          assert.equal(stamped1[28], undefined);
          done();
        });
      });

      test('undo: splice - add to middle (using splice)', function(done) {
        unconfigured.splice('items', 1, 3);
        setTimeout(function() {
          var stamped1 = Polymer.dom(unconfigured1.root).querySelectorAll('*:not(template)');
          assert.equal(stamped1.length, 2 + 2*3 + 2*3*3, 'total stamped count incorrect');
          assert.equal(stamped1[0].itemaProp, 'prop-3');
          assert.equal(stamped1[0].indexa, 0);
          assert.equal(stamped1[1].itembProp, 'prop-3-1');
          assert.equal(stamped1[1].indexa, 0);
          assert.equal(stamped1[1].indexb, 0);
          assert.equal(stamped1[2].itemcProp, 'prop-3-1-1');
          assert.equal(stamped1[2].indexa, 0);
          assert.equal(stamped1[2].indexb, 0);
          assert.equal(stamped1[2].indexc, 0);
          assert.equal(stamped1[23].itemcProp, 'prop-1-3-1');
          assert.equal(stamped1[23].indexa, 1);
          assert.equal(stamped1[23].indexb, 2);
          assert.equal(stamped1[23].indexc, 0);
          assert.equal(stamped1[24].itemcProp, 'prop-1-3-2');
          assert.equal(stamped1[24].indexa, 1);
          assert.equal(stamped1[24].indexb, 2);
          assert.equal(stamped1[24].indexc, 1);
          assert.equal(stamped1[25].itemcProp, 'prop-1-3-3');
          assert.equal(stamped1[25].indexa, 1);
          assert.equal(stamped1[25].indexb, 2);
          assert.equal(stamped1[25].indexc, 2);
          assert.equal(stamped1[26], undefined);
          done();
        });
      });

      test('splice - replace in middle', function(done) {
        removed = unconfigured.splice('items', 1, 2, a={prop: 'a'}, m={prop: 'item*2'}, z={prop: 'z'});
        setTimeout(function() {
          var stamped1 = Polymer.dom(unconfigured1.root).querySelectorAll('*:not(template)');
          assert.equal(stamped1.length, 2 + 1 + 1*3 + 1*3*3, 'total stamped count incorrect');
          assert.equal(stamped1[0].itemaProp, 'z');
          assert.equal(stamped1[0].indexa, 0);
          assert.equal(stamped1[1].itemaProp, 'prop-1');
          assert.equal(stamped1[1].indexa, 1);
          assert.equal(stamped1[2].itembProp, 'prop-1-1');
          assert.equal(stamped1[2].indexa, 1);
          assert.equal(stamped1[2].indexb, 0);
          assert.equal(stamped1[3].itemcProp, 'prop-1-1-1');
          assert.equal(stamped1[3].indexa, 1);
          assert.equal(stamped1[3].indexb, 0);
          assert.equal(stamped1[3].indexc, 0);
          assert.equal(stamped1[13].itemcProp, 'prop-1-3-3');
          assert.equal(stamped1[13].indexa, 1);
          assert.equal(stamped1[13].indexb, 2);
          assert.equal(stamped1[13].indexc, 2);
          assert.equal(stamped1[14].itemaProp, 'a');
          assert.equal(stamped1[14].indexa, 2);
          assert.equal(stamped1[15], undefined);
          done();
        });
      });

      test('undo: splice - replace in middle (using splice)', function(done) {
        unconfigured.splice('items', 1, 3, removed[0], removed[1]);
        setTimeout(function() {
          var stamped1 = Polymer.dom(unconfigured1.root).querySelectorAll('*:not(template)');
          assert.equal(stamped1.length, 2 + 2*3 + 2*3*3, 'total stamped count incorrect');
          assert.equal(stamped1[0].itemaProp, 'prop-3');
          assert.equal(stamped1[0].indexa, 0);
          assert.equal(stamped1[1].itembProp, 'prop-3-1');
          assert.equal(stamped1[1].indexa, 0);
          assert.equal(stamped1[1].indexb, 0);
          assert.equal(stamped1[2].itemcProp, 'prop-3-1-1');
          assert.equal(stamped1[2].indexa, 0);
          assert.equal(stamped1[2].indexb, 0);
          assert.equal(stamped1[2].indexc, 0);
          assert.equal(stamped1[23].itemcProp, 'prop-1-3-1');
          assert.equal(stamped1[23].indexa, 1);
          assert.equal(stamped1[23].indexb, 2);
          assert.equal(stamped1[23].indexc, 0);
          assert.equal(stamped1[24].itemcProp, 'prop-1-3-2');
          assert.equal(stamped1[24].indexa, 1);
          assert.equal(stamped1[24].indexb, 2);
          assert.equal(stamped1[24].indexc, 1);
          assert.equal(stamped1[25].itemcProp, 'prop-1-3-3');
          assert.equal(stamped1[25].indexa, 1);
          assert.equal(stamped1[25].indexb, 2);
          assert.equal(stamped1[25].indexc, 2);
          assert.equal(stamped1[26], undefined);
          done();
        });
      });

    });

    suite('multiple mutations in same turn', function() {

      test('array sort, no filter: unshift+pop', function(done) {
        // repeater 1
        var stamped1 = Polymer.dom(primitive.$.container1).querySelectorAll('*:not(template)');
        assert.equal(stamped1[0].itemaProp, 'a');
        assert.equal(stamped1[1].itemaProp, 'b');
        assert.equal(stamped1[2].itemaProp, 'c');
        assert.equal(stamped1[3].itemaProp, 'd');
        assert.equal(stamped1[4].itemaProp, 'e');
        primitive.unshift('items', 'new1');
        primitive.pop('items');
        setTimeout(function() {
          stamped1 = Polymer.dom(primitive.$.container1).querySelectorAll('*:not(template)');
          assert.equal(stamped1[0].itemaProp, 'new1');
          assert.equal(stamped1[1].itemaProp, 'a');
          assert.equal(stamped1[2].itemaProp, 'b');
          assert.equal(stamped1[3].itemaProp, 'c');
          assert.equal(stamped1[4].itemaProp, 'd');
          primitive.unshift('items', 'new2');
          primitive.pop('items');
          primitive.unshift('items', 'new3');
          primitive.pop('items');
          setTimeout(function() {
            stamped1 = Polymer.dom(primitive.$.container1).querySelectorAll('*:not(template)');
            assert.equal(stamped1[0].itemaProp, 'new3');
            assert.equal(stamped1[1].itemaProp, 'new2');
            assert.equal(stamped1[2].itemaProp, 'new1');
            assert.equal(stamped1[3].itemaProp, 'a');
            assert.equal(stamped1[4].itemaProp, 'b');
            primitive.shift('items');
            primitive.push('items', 'c');
            setTimeout(function() {
              stamped1 = Polymer.dom(primitive.$.container1).querySelectorAll('*:not(template)');
              assert.equal(stamped1[0].itemaProp, 'new2');
              assert.equal(stamped1[1].itemaProp, 'new1');
              assert.equal(stamped1[2].itemaProp, 'a');
              assert.equal(stamped1[3].itemaProp, 'b');
              assert.equal(stamped1[4].itemaProp, 'c');
              primitive.shift('items');
              primitive.push('items', 'd');
              primitive.shift('items');
              primitive.push('items', 'e');
              setTimeout(function() {
                stamped1 = Polymer.dom(primitive.$.container1).querySelectorAll('*:not(template)');
                assert.equal(stamped1[0].itemaProp, 'a');
                assert.equal(stamped1[1].itemaProp, 'b');
                assert.equal(stamped1[2].itemaProp, 'c');
                assert.equal(stamped1[3].itemaProp, 'd');
                assert.equal(stamped1[4].itemaProp, 'e');
                done();
              });
            });
          });
        });
      });

      test('array sort, no filter: insertions', function(done) {
        // repeater 1
        var stamped1 = Polymer.dom(primitive.$.container1).querySelectorAll('*:not(template)');
        assert.equal(stamped1[0].itemaProp, 'a');
        assert.equal(stamped1[1].itemaProp, 'b');
        assert.equal(stamped1[2].itemaProp, 'c');
        assert.equal(stamped1[3].itemaProp, 'd');
        assert.equal(stamped1[4].itemaProp, 'e');
        primitive.splice('items', 1, 0, 'new2', 'new3');
        primitive.splice('items', 0, 0, 'new1');
        primitive.splice('items', 8, 0, 'new5');
        primitive.splice('items', 5, 0, 'new4');
        setTimeout(function() {
          stamped1 = Polymer.dom(primitive.$.container1).querySelectorAll('*:not(template)');
          assert.equal(stamped1[0].itemaProp, 'new1');
          assert.equal(stamped1[1].itemaProp, 'a');
          assert.equal(stamped1[2].itemaProp, 'new2');
          assert.equal(stamped1[3].itemaProp, 'new3');
          assert.equal(stamped1[4].itemaProp, 'b');
          assert.equal(stamped1[5].itemaProp, 'new4');
          assert.equal(stamped1[6].itemaProp, 'c');
          assert.equal(stamped1[7].itemaProp, 'd');
          assert.equal(stamped1[8].itemaProp, 'e');
          assert.equal(stamped1[9].itemaProp, 'new5');
          primitive.arrayDelete('items', 'new5');
          primitive.arrayDelete('items', 'new3');
          primitive.arrayDelete('items', 'new1');
          primitive.arrayDelete('items', 'new2');
          primitive.arrayDelete('items', 'new4');
          setTimeout(function() {
            stamped1 = Polymer.dom(primitive.$.container1).querySelectorAll('*:not(template)');
            assert.equal(stamped1[0].itemaProp, 'a');
            assert.equal(stamped1[1].itemaProp, 'b');
            assert.equal(stamped1[2].itemaProp, 'c');
            assert.equal(stamped1[3].itemaProp, 'd');
            assert.equal(stamped1[4].itemaProp, 'e');
            done();
          });
        });
      });

      test('array sort, no filter: insert & remove', function(done) {
        // repeater 1
        var stamped1 = Polymer.dom(primitive.$.container1).querySelectorAll('*:not(template)');
        assert.equal(stamped1[0].itemaProp, 'a');
        assert.equal(stamped1[1].itemaProp, 'b');
        assert.equal(stamped1[2].itemaProp, 'c');
        assert.equal(stamped1[3].itemaProp, 'd');
        assert.equal(stamped1[4].itemaProp, 'e');
        primitive.splice('items', 1, 0, 'new1', 'new2', 'new3');
        primitive.splice('items', 3, 1);
        primitive.splice('items', 4, 0, 'new4', 'new5', 'new6');
        primitive.splice('items', 4, 2);
        primitive.splice('items', 4, 1);
        primitive.splice('items', 1, 2);
        setTimeout(function() {
          stamped1 = Polymer.dom(primitive.$.container1).querySelectorAll('*:not(template)');
          assert.equal(stamped1[0].itemaProp, 'a');
          assert.equal(stamped1[1].itemaProp, 'b');
          assert.equal(stamped1[2].itemaProp, 'c');
          assert.equal(stamped1[3].itemaProp, 'd');
          assert.equal(stamped1[4].itemaProp, 'e');
          done();
        });
      });

      test('array sort, filtered: unshift+pop', function(done) {
        primitive.$.repeater1.filter = function(s) {
          return s.indexOf('new2') < 0;
        };
        // repeater 1
        var stamped1 = Polymer.dom(primitive.$.container1).querySelectorAll('*:not(template)');
        assert.equal(stamped1[0].itemaProp, 'a');
        assert.equal(stamped1[1].itemaProp, 'b');
        assert.equal(stamped1[2].itemaProp, 'c');
        assert.equal(stamped1[3].itemaProp, 'd');
        assert.equal(stamped1[4].itemaProp, 'e');
        primitive.unshift('items', 'new1');
        primitive.pop('items');
        setTimeout(function() {
          stamped1 = Polymer.dom(primitive.$.container1).querySelectorAll('*:not(template)');
          assert.equal(stamped1[0].itemaProp, 'new1');
          assert.equal(stamped1[1].itemaProp, 'a');
          assert.equal(stamped1[2].itemaProp, 'b');
          assert.equal(stamped1[3].itemaProp, 'c');
          assert.equal(stamped1[4].itemaProp, 'd');
          primitive.unshift('items', 'new2');
          primitive.pop('items');
          primitive.unshift('items', 'new3');
          primitive.pop('items');
          setTimeout(function() {
            stamped1 = Polymer.dom(primitive.$.container1).querySelectorAll('*:not(template)');
            assert.equal(stamped1[0].itemaProp, 'new3');
            assert.equal(stamped1[1].itemaProp, 'new1');
            assert.equal(stamped1[2].itemaProp, 'a');
            assert.equal(stamped1[3].itemaProp, 'b');
            primitive.shift('items');
            primitive.push('items', 'c');
            setTimeout(function() {
              stamped1 = Polymer.dom(primitive.$.container1).querySelectorAll('*:not(template)');
              assert.equal(stamped1[0].itemaProp, 'new1');
              assert.equal(stamped1[1].itemaProp, 'a');
              assert.equal(stamped1[2].itemaProp, 'b');
              assert.equal(stamped1[3].itemaProp, 'c');
              primitive.shift('items');
              primitive.push('items', 'd');
              primitive.shift('items');
              primitive.push('items', 'e');
              setTimeout(function() {
                stamped1 = Polymer.dom(primitive.$.container1).querySelectorAll('*:not(template)');
                assert.equal(stamped1[0].itemaProp, 'a');
                assert.equal(stamped1[1].itemaProp, 'b');
                assert.equal(stamped1[2].itemaProp, 'c');
                assert.equal(stamped1[3].itemaProp, 'd');
                assert.equal(stamped1[4].itemaProp, 'e');
                done();
              });
            });
          });
        });
      });

      test('array sort, filtered: insertions', function(done) {
        // repeater 1
        var stamped1 = Polymer.dom(primitive.$.container1).querySelectorAll('*:not(template)');
        assert.equal(stamped1[0].itemaProp, 'a');
        assert.equal(stamped1[1].itemaProp, 'b');
        assert.equal(stamped1[2].itemaProp, 'c');
        assert.equal(stamped1[3].itemaProp, 'd');
        assert.equal(stamped1[4].itemaProp, 'e');
        primitive.splice('items', 1, 0, 'new2', 'new3');
        primitive.splice('items', 0, 0, 'new1');
        primitive.splice('items', 8, 0, 'new5');
        primitive.splice('items', 5, 0, 'new4');
        setTimeout(function() {
          stamped1 = Polymer.dom(primitive.$.container1).querySelectorAll('*:not(template)');
          assert.equal(stamped1[0].itemaProp, 'new1');
          assert.equal(stamped1[1].itemaProp, 'a');
          assert.equal(stamped1[2].itemaProp, 'new3');
          assert.equal(stamped1[3].itemaProp, 'b');
          assert.equal(stamped1[4].itemaProp, 'new4');
          assert.equal(stamped1[5].itemaProp, 'c');
          assert.equal(stamped1[6].itemaProp, 'd');
          assert.equal(stamped1[7].itemaProp, 'e');
          assert.equal(stamped1[8].itemaProp, 'new5');
          primitive.arrayDelete('items', 'new5');
          primitive.arrayDelete('items', 'new3');
          primitive.arrayDelete('items', 'new1');
          primitive.arrayDelete('items', 'new2');
          primitive.arrayDelete('items', 'new4');
          setTimeout(function() {
            stamped1 = Polymer.dom(primitive.$.container1).querySelectorAll('*:not(template)');
            assert.equal(stamped1[0].itemaProp, 'a');
            assert.equal(stamped1[1].itemaProp, 'b');
            assert.equal(stamped1[2].itemaProp, 'c');
            assert.equal(stamped1[3].itemaProp, 'd');
            assert.equal(stamped1[4].itemaProp, 'e');
            done();
          });
        });
      });

      test('array sort, filtered: insert & remove', function(done) {
        // repeater 1
        var stamped1 = Polymer.dom(primitive.$.container1).querySelectorAll('*:not(template)');
        assert.equal(stamped1[0].itemaProp, 'a');
        assert.equal(stamped1[1].itemaProp, 'b');
        assert.equal(stamped1[2].itemaProp, 'c');
        assert.equal(stamped1[3].itemaProp, 'd');
        assert.equal(stamped1[4].itemaProp, 'e');
        primitive.splice('items', 1, 0, 'new1', 'new2', 'new3');
        primitive.splice('items', 3, 1);
        primitive.splice('items', 4, 0, 'new4', 'new5', 'new6');
        primitive.splice('items', 4, 2);
        primitive.splice('items', 4, 1);
        primitive.splice('items', 1, 2);
        primitive.$.repeater1.filter = null;
        setTimeout(function() {
          stamped1 = Polymer.dom(primitive.$.container1).querySelectorAll('*:not(template)');
          assert.equal(stamped1[0].itemaProp, 'a');
          assert.equal(stamped1[1].itemaProp, 'b');
          assert.equal(stamped1[2].itemaProp, 'c');
          assert.equal(stamped1[3].itemaProp, 'd');
          assert.equal(stamped1[4].itemaProp, 'e');
          done();
        });
      });

      test('view sort, no filter: unshift+pop', function(done) {
        primitive.$.repeater1.sort = function(a, b) {
          return b.localeCompare(a);
        };
        setTimeout(function() {
          // repeater 1
          var stamped1 = Polymer.dom(primitive.$.container1).querySelectorAll('*:not(template)');
          assert.equal(stamped1[0].itemaProp, 'e');
          assert.equal(stamped1[1].itemaProp, 'd');
          assert.equal(stamped1[2].itemaProp, 'c');
          assert.equal(stamped1[3].itemaProp, 'b');
          assert.equal(stamped1[4].itemaProp, 'a');
          primitive.unshift('items', 'new1');
          primitive.pop('items');
          setTimeout(function() {
            stamped1 = Polymer.dom(primitive.$.container1).querySelectorAll('*:not(template)');
            assert.equal(stamped1[0].itemaProp, 'new1');
            assert.equal(stamped1[1].itemaProp, 'd');
            assert.equal(stamped1[2].itemaProp, 'c');
            assert.equal(stamped1[3].itemaProp, 'b');
            assert.equal(stamped1[4].itemaProp, 'a');
            primitive.unshift('items', 'new2');
            primitive.pop('items');
            primitive.unshift('items', 'new3');
            primitive.pop('items');
            setTimeout(function() {
              stamped1 = Polymer.dom(primitive.$.container1).querySelectorAll('*:not(template)');
              assert.equal(stamped1[0].itemaProp, 'new3');
              assert.equal(stamped1[1].itemaProp, 'new2');
              assert.equal(stamped1[2].itemaProp, 'new1');
              assert.equal(stamped1[3].itemaProp, 'b');
              assert.equal(stamped1[4].itemaProp, 'a');
              primitive.shift('items');
              primitive.push('items', 'c');
              setTimeout(function() {
                stamped1 = Polymer.dom(primitive.$.container1).querySelectorAll('*:not(template)');
                assert.equal(stamped1[0].itemaProp, 'new2');
                assert.equal(stamped1[1].itemaProp, 'new1');
                assert.equal(stamped1[2].itemaProp, 'c');
                assert.equal(stamped1[3].itemaProp, 'b');
                assert.equal(stamped1[4].itemaProp, 'a');
                primitive.shift('items');
                primitive.push('items', 'd');
                primitive.shift('items');
                primitive.push('items', 'e');
                setTimeout(function() {
                  stamped1 = Polymer.dom(primitive.$.container1).querySelectorAll('*:not(template)');
                  assert.equal(stamped1[0].itemaProp, 'e');
                  assert.equal(stamped1[1].itemaProp, 'd');
                  assert.equal(stamped1[2].itemaProp, 'c');
                  assert.equal(stamped1[3].itemaProp, 'b');
                  assert.equal(stamped1[4].itemaProp, 'a');
                  done();
                });
              });
            });
          });
        });
      });

      test('view sort, no filter: insertions', function(done) {
        // repeater 1
        var stamped1 = Polymer.dom(primitive.$.container1).querySelectorAll('*:not(template)');
        assert.equal(stamped1[0].itemaProp, 'e');
        assert.equal(stamped1[1].itemaProp, 'd');
        assert.equal(stamped1[2].itemaProp, 'c');
        assert.equal(stamped1[3].itemaProp, 'b');
        assert.equal(stamped1[4].itemaProp, 'a');
        primitive.splice('items', 1, 0, 'new2', 'new3');
        primitive.splice('items', 0, 0, 'new1');
        primitive.splice('items', 8, 0, 'new5');
        primitive.splice('items', 5, 0, 'new4');
        setTimeout(function() {
          stamped1 = Polymer.dom(primitive.$.container1).querySelectorAll('*:not(template)');
          assert.equal(stamped1[0].itemaProp, 'new5');
          assert.equal(stamped1[1].itemaProp, 'new4');
          assert.equal(stamped1[2].itemaProp, 'new3');
          assert.equal(stamped1[3].itemaProp, 'new2');
          assert.equal(stamped1[4].itemaProp, 'new1');
          assert.equal(stamped1[5].itemaProp, 'e');
          assert.equal(stamped1[6].itemaProp, 'd');
          assert.equal(stamped1[7].itemaProp, 'c');
          assert.equal(stamped1[8].itemaProp, 'b');
          assert.equal(stamped1[9].itemaProp, 'a');
          primitive.arrayDelete('items', 'new5');
          primitive.arrayDelete('items', 'new3');
          primitive.arrayDelete('items', 'new1');
          primitive.arrayDelete('items', 'new2');
          primitive.arrayDelete('items', 'new4');
          setTimeout(function() {
            stamped1 = Polymer.dom(primitive.$.container1).querySelectorAll('*:not(template)');
            assert.equal(stamped1[0].itemaProp, 'e');
            assert.equal(stamped1[1].itemaProp, 'd');
            assert.equal(stamped1[2].itemaProp, 'c');
            assert.equal(stamped1[3].itemaProp, 'b');
            assert.equal(stamped1[4].itemaProp, 'a');
            done();
          });
        });
      });

      test('view sort, no filter: insert & remove', function(done) {
        // repeater 1
        var stamped1 = Polymer.dom(primitive.$.container1).querySelectorAll('*:not(template)');
        assert.equal(stamped1[0].itemaProp, 'e');
        assert.equal(stamped1[1].itemaProp, 'd');
        assert.equal(stamped1[2].itemaProp, 'c');
        assert.equal(stamped1[3].itemaProp, 'b');
        assert.equal(stamped1[4].itemaProp, 'a');
        primitive.splice('items', 1, 0, 'new1', 'new2', 'new3');
        primitive.splice('items', 3, 1);
        primitive.splice('items', 4, 0, 'new4', 'new5', 'new6');
        primitive.splice('items', 4, 2);
        primitive.splice('items', 4, 1);
        primitive.splice('items', 1, 2);
        setTimeout(function() {
          stamped1 = Polymer.dom(primitive.$.container1).querySelectorAll('*:not(template)');
          assert.equal(stamped1[0].itemaProp, 'e');
          assert.equal(stamped1[1].itemaProp, 'd');
          assert.equal(stamped1[2].itemaProp, 'c');
          assert.equal(stamped1[3].itemaProp, 'b');
          assert.equal(stamped1[4].itemaProp, 'a');
          done();
        });
      });

      test('view sort, filtered: unshift+pop', function(done) {
        primitive.$.repeater1.filter = function(s) {
          return s.indexOf('new2') < 0;
        };
        setTimeout(function() {
          // repeater 1
          var stamped1 = Polymer.dom(primitive.$.container1).querySelectorAll('*:not(template)');
          assert.equal(stamped1[0].itemaProp, 'e');
          assert.equal(stamped1[1].itemaProp, 'd');
          assert.equal(stamped1[2].itemaProp, 'c');
          assert.equal(stamped1[3].itemaProp, 'b');
          assert.equal(stamped1[4].itemaProp, 'a');
          primitive.unshift('items', 'new1');
          primitive.pop('items');
          setTimeout(function() {
            stamped1 = Polymer.dom(primitive.$.container1).querySelectorAll('*:not(template)');
            assert.equal(stamped1[0].itemaProp, 'new1');
            assert.equal(stamped1[1].itemaProp, 'd');
            assert.equal(stamped1[2].itemaProp, 'c');
            assert.equal(stamped1[3].itemaProp, 'b');
            assert.equal(stamped1[4].itemaProp, 'a');
            primitive.unshift('items', 'new2');
            primitive.pop('items');
            primitive.unshift('items', 'new3');
            primitive.pop('items');
            setTimeout(function() {
              stamped1 = Polymer.dom(primitive.$.container1).querySelectorAll('*:not(template)');
              assert.equal(stamped1[0].itemaProp, 'new3');
              assert.equal(stamped1[1].itemaProp, 'new1');
              assert.equal(stamped1[2].itemaProp, 'b');
              assert.equal(stamped1[3].itemaProp, 'a');
              primitive.shift('items');
              primitive.push('items', 'c');
              setTimeout(function() {
                stamped1 = Polymer.dom(primitive.$.container1).querySelectorAll('*:not(template)');
                assert.equal(stamped1[0].itemaProp, 'new1');
                assert.equal(stamped1[1].itemaProp, 'c');
                assert.equal(stamped1[2].itemaProp, 'b');
                assert.equal(stamped1[3].itemaProp, 'a');
                primitive.shift('items');
                primitive.push('items', 'd');
                primitive.shift('items');
                primitive.push('items', 'e');
                setTimeout(function() {
                  stamped1 = Polymer.dom(primitive.$.container1).querySelectorAll('*:not(template)');
                  assert.equal(stamped1[0].itemaProp, 'e');
                  assert.equal(stamped1[1].itemaProp, 'd');
                  assert.equal(stamped1[2].itemaProp, 'c');
                  assert.equal(stamped1[3].itemaProp, 'b');
                  assert.equal(stamped1[4].itemaProp, 'a');
                  done();
                });
              });
            });
          });
        });
      });

      test('view sort, no filter: insertions', function(done) {
        // repeater 1
        var stamped1 = Polymer.dom(primitive.$.container1).querySelectorAll('*:not(template)');
        assert.equal(stamped1[0].itemaProp, 'e');
        assert.equal(stamped1[1].itemaProp, 'd');
        assert.equal(stamped1[2].itemaProp, 'c');
        assert.equal(stamped1[3].itemaProp, 'b');
        assert.equal(stamped1[4].itemaProp, 'a');
        primitive.splice('items', 1, 0, 'new2', 'new3');
        primitive.splice('items', 0, 0, 'new1');
        primitive.splice('items', 8, 0, 'new5');
        primitive.splice('items', 5, 0, 'new4');
        setTimeout(function() {
          stamped1 = Polymer.dom(primitive.$.container1).querySelectorAll('*:not(template)');
          assert.equal(stamped1[0].itemaProp, 'new5');
          assert.equal(stamped1[1].itemaProp, 'new4');
          assert.equal(stamped1[2].itemaProp, 'new3');
          assert.equal(stamped1[3].itemaProp, 'new1');
          assert.equal(stamped1[4].itemaProp, 'e');
          assert.equal(stamped1[5].itemaProp, 'd');
          assert.equal(stamped1[6].itemaProp, 'c');
          assert.equal(stamped1[7].itemaProp, 'b');
          assert.equal(stamped1[8].itemaProp, 'a');
          primitive.arrayDelete('items', 'new5');
          primitive.arrayDelete('items', 'new3');
          primitive.arrayDelete('items', 'new1');
          primitive.arrayDelete('items', 'new2');
          primitive.arrayDelete('items', 'new4');
          setTimeout(function() {
            stamped1 = Polymer.dom(primitive.$.container1).querySelectorAll('*:not(template)');
            assert.equal(stamped1[0].itemaProp, 'e');
            assert.equal(stamped1[1].itemaProp, 'd');
            assert.equal(stamped1[2].itemaProp, 'c');
            assert.equal(stamped1[3].itemaProp, 'b');
            assert.equal(stamped1[4].itemaProp, 'a');
            done();
          });
        });
      });

      test('view sort, no filter: insert & remove', function(done) {
        // repeater 1
        var stamped1 = Polymer.dom(primitive.$.container1).querySelectorAll('*:not(template)');
        assert.equal(stamped1[0].itemaProp, 'e');
        assert.equal(stamped1[1].itemaProp, 'd');
        assert.equal(stamped1[2].itemaProp, 'c');
        assert.equal(stamped1[3].itemaProp, 'b');
        assert.equal(stamped1[4].itemaProp, 'a');
        primitive.splice('items', 1, 0, 'new1', 'new2', 'new3');
        primitive.splice('items', 3, 1);
        primitive.splice('items', 4, 0, 'new4', 'new5', 'new6');
        primitive.splice('items', 4, 2);
        primitive.splice('items', 4, 1);
        primitive.splice('items', 1, 2);
        setTimeout(function() {
          stamped1 = Polymer.dom(primitive.$.container1).querySelectorAll('*:not(template)');
          assert.equal(stamped1[0].itemaProp, 'e');
          assert.equal(stamped1[1].itemaProp, 'd');
          assert.equal(stamped1[2].itemaProp, 'c');
          assert.equal(stamped1[3].itemaProp, 'b');
          assert.equal(stamped1[4].itemaProp, 'a');
          primitive.$.repeater1.filter = null;
          primitive.$.repeater1.sort = null;
          setTimeout(function() {
            stamped1 = Polymer.dom(primitive.$.container1).querySelectorAll('*:not(template)');
            assert.equal(stamped1[0].itemaProp, 'a');
            assert.equal(stamped1[1].itemaProp, 'b');
            assert.equal(stamped1[2].itemaProp, 'c');
            assert.equal(stamped1[3].itemaProp, 'd');
            assert.equal(stamped1[4].itemaProp, 'e');
            done();
          });
        });
      });

    });

    suite('item changing on instance', function() {

      test('primitive values - initial stamping', function() {
        // repeater 1
        var stamped1 = Polymer.dom(primitive.$.container1).querySelectorAll('*:not(template)');
        assert.equal(stamped1[0].itemaProp, 'a');
        assert.equal(stamped1[1].itemaProp, 'b');
        assert.equal(stamped1[2].itemaProp, 'c');
        assert.equal(stamped1[3].itemaProp, 'd');
        assert.equal(stamped1[4].itemaProp, 'e');
        // repeater 2
        var stamped2 = Polymer.dom(primitive.$.container2).querySelectorAll('*:not(template)');
        assert.equal(stamped2[0].itemaProp, 'a');
        assert.equal(stamped2[1].itemaProp, 'b');
        assert.equal(stamped2[2].itemaProp, 'c');
        assert.equal(stamped2[3].itemaProp, 'd');
        assert.equal(stamped2[4].itemaProp, 'e');
      });

      test('primitive values - change from inside', function() {
        var stamped1 = Polymer.dom(primitive.$.container1).querySelectorAll('*:not(template)');
        var stamped2 = Polymer.dom(primitive.$.container2).querySelectorAll('*:not(template)');
        var old = stamped1[2].itemaProp;
        // Change middle item
        stamped1[2].itemaProp = 'change!';
        assert.equal(primitive.items[2], 'change!');
        assert.equal(stamped2[2].itemaProp, 'change!');
        // Revert
        stamped2[2].itemaProp = old;
        assert.equal(primitive.items[2], 'c');
        assert.equal(stamped1[2].itemaProp, 'c');
      });

      test('primitive values - sorted', function() {
        // Apply sort
        primitive.$.repeater1.sort = function(a, b) {
          return b.localeCompare(a);
        };
        primitive.$.repeater1.render();
        var stamped1 = Polymer.dom(primitive.$.container1).querySelectorAll('*:not(template)');
        var stamped2 = Polymer.dom(primitive.$.container2).querySelectorAll('*:not(template)');
        var old = stamped1[0].itemaProp;
        // Change last item (first rendered in #1, last rendered in #2)
        stamped1[0].itemaProp = 'change!';
        assert.equal(primitive.items[4], 'change!');
        assert.equal(stamped2[4].itemaProp, 'change!');
        // Revert
        stamped2[4].itemaProp = old;
        assert.equal(primitive.items[4], 'e');
        assert.equal(stamped1[0].itemaProp, 'e');
        primitive.$.repeater1.sort = null;
        primitive.$.repeater1.render();
      });

      test('structured values - initial stamping', function() {
        var stamped1 = Polymer.dom(unconfigured1.root).querySelectorAll('*:not(template)');
        var stamped2 = Polymer.dom(unconfigured2.root).querySelectorAll('*:not(template)');
        assert.equal(stamped1[0].itemaProp, 'prop-1');
        assert.equal(stamped2[0].itemaProp, 'prop-1');
      });

      test('structured values - change from inside', function() {
        var stamped1 = Polymer.dom(unconfigured1.root).querySelectorAll('*:not(template)');
        var stamped2 = Polymer.dom(unconfigured2.root).querySelectorAll('*:not(template)');
        var old = unconfigured.items[0];
        // Change first item
        unconfigured1.$.repeater._instances[0].itema = {prop: 'change!'};
        assert.equal(stamped1[0].itemaProp, 'change!');
        assert.equal(stamped2[0].itemaProp, 'change!');
        // Revert
        unconfigured2.$.repeater._instances[0].itema = old;
        assert.equal(stamped1[0].itemaProp, 'prop-1');
        assert.equal(stamped2[0].itemaProp, 'prop-1');
      });

      test('structured values - sorted', function() {
        unconfigured1.$.repeater.sort = function(a, b) {
          return b.prop == a.prop ? 0 : b.prop < a.prop ? -1 : 1;
        };
        unconfigured1.$.repeater.render();
        var stamped1 = Polymer.dom(unconfigured1.root).querySelectorAll('*:not(template)');
        var stamped2 = Polymer.dom(unconfigured2.root).querySelectorAll('*:not(template)');
        var old = unconfigured.items[2];
        // Change last item (first rendered in #1, last rendered in #2)
        unconfigured1.$.repeater._instances[0].itema = {prop: 'change!'};
        assert.equal(stamped1[0].itemaProp, 'change!');
        assert.equal(stamped2[26].itemaProp, 'change!');
        // Revert
        unconfigured2.$.repeater._instances[2].itema = old;
        assert.equal(stamped1[0].itemaProp, 'prop-3');
        assert.equal(stamped2[26].itemaProp, 'prop-3');
        unconfigured1.$.repeater.sort = null;
        unconfigured1.$.repeater.render();
      });

    });

    suite('external change & notification', function() {

      test('in-place sort', function(done) {
        var items = [
          173, 166, 145, 755, 907,
          836, 564, 721, 540, 372,
          244, 145, 525, 958, 595,
          207, 103, 602, 769, 190];
        primitive.items = items;
        setTimeout(function() {
          var stamped1 = Polymer.dom(primitive.$.container1).querySelectorAll('*:not(template)');
          for (var i=0; i<items.length; i++) {
            assert.equal(stamped1[i].itemaProp, items[i]);
          }
          var prev = items.slice();
          items.sort();
          var splices = Polymer.ArraySplice.calculateSplices(items, prev);
          var change = {
            keySplices: Polymer.Collection.applySplices(items, splices),
            indexSplices: splices
          };
          primitive.set('items.splices', change);
          setTimeout(function() {
            var stamped1 = Polymer.dom(primitive.$.container1).querySelectorAll('*:not(template)');
            for (var i=0; i<items.length; i++) {
              assert.equal(stamped1[i].itemaProp, items[i]);
            }
            done();
          });
        });
      });

    });

    suite('repeater API', function() {

      test('modelForElement', function() {
        var dom = Polymer.dom(unconfigured1.root);
        var stamped1 = dom.querySelectorAll('*:not(template)');
        var repeater1 = dom.querySelector('template[as=itema]');
        var repeater2 = dom.querySelector('template[as=itemb]');
        var repeater3 = dom.querySelector('template[as=itemc]');

        model = repeater1.modelForElement(stamped1[4]);
        assert.equal(model.itema.prop, 'prop-1');

        model = repeater2.modelForElement(stamped1[4]);
        assert.equal(model.itema.prop, 'prop-1');
        assert.equal(model.itemb.prop, 'prop-1-1');

        model = repeater3.modelForElement(stamped1[4]);
        assert.equal(model.itema.prop, 'prop-1');
        assert.equal(model.itemb.prop, 'prop-1-1');
        assert.equal(model.itemc.prop, 'prop-1-1-3');
      });

      test('indexForElement', function() {
        var dom = Polymer.dom(unconfigured1.root);
        var stamped1 = dom.querySelectorAll('*:not(template)');
        var repeater1 = dom.querySelector('template[as=itema]');
        var repeater2 = dom.querySelector('template[as=itemb]');
        var repeater3 = dom.querySelector('template[as=itemc]');

        assert.equal(repeater1.indexForElement(stamped1[4]), 0);
        assert.equal(repeater2.indexForElement(stamped1[4]), 0);
        assert.equal(repeater3.indexForElement(stamped1[4]), 2);
      });

      test('indexForElement', function() {
        var dom = Polymer.dom(unconfigured1.root);
        var stamped1 = dom.querySelectorAll('*:not(template)');
        var repeater1 = dom.querySelector('template[as=itema]');
        var repeater2 = dom.querySelector('template[as=itemb]');
        var repeater3 = dom.querySelector('template[as=itemc]');

        assert.equal(repeater1.itemForElement(stamped1[4]).prop, 'prop-1');
        assert.equal(repeater2.itemForElement(stamped1[4]).prop, 'prop-1-1');
        assert.equal(repeater3.itemForElement(stamped1[4]).prop, 'prop-1-1-3');
      });

      test('keyForElement', function() {
        var dom = Polymer.dom(unconfigured1.root);
        var stamped1 = dom.querySelectorAll('*:not(template)');
        var repeater1 = dom.querySelector('template[as=itema]');
        var repeater2 = dom.querySelector('template[as=itemb]');
        var repeater3 = dom.querySelector('template[as=itemc]');
        var items1 = unconfigured1.items;
        var items2 = unconfigured1.items[0].items;
        var items3 = unconfigured1.items[0].items[0].items;
        var coll1 = Polymer.Collection.get(items1);
        var coll2 = Polymer.Collection.get(items2);
        var coll3 = Polymer.Collection.get(items3);

        assert.equal(repeater1.keyForElement(stamped1[4]), coll1.getKey(items1[0]));
        assert.equal(repeater2.keyForElement(stamped1[4]), coll2.getKey(items2[0]));
        assert.equal(repeater3.keyForElement(stamped1[4]), coll3.getKey(items3[2]));
      });

      test('renderedItemCount', function() {
         var repeater1 = primitive.$.repeater1;
         primitive.items = [ 'a', 'b', 'c', 'd', 'e' ];
         repeater1.render();
         assert.equal(repeater1.renderedItemCount, 5, 'renderedItemCount is incorrect');
         repeater1.renderedItemCount = 0;
         assert.equal(repeater1.renderedItemCount, 5, 'renderedItemCount is writable');
         repeater1.filter = function(item) {
           return (item != 'a' && item != 'e');
         };
         repeater1.render();
         assert.equal(repeater1.renderedItemCount, 3, 'renderedItemCount incorrect after filter');
         // reset repeater
         repeater1.filter = undefined;
         repeater1.render();
      });

      test('__hideTemplateChildren__', function() {
        // Initially all showing
        var stamped1 = Polymer.dom(primitive.$.container1).querySelectorAll('*:not(template)');
        assert.equal(getComputedStyle(stamped1[0]).display, 'block');
        assert.equal(getComputedStyle(stamped1[1]).display, 'block');
        assert.equal(getComputedStyle(stamped1[2]).display, 'block');
        assert.equal(getComputedStyle(stamped1[3]).display, 'block');
        assert.equal(getComputedStyle(stamped1[4]).display, 'block');

        // Hide all
        primitive.$.repeater1.__hideTemplateChildren__ = true;
        assert.equal(getComputedStyle(stamped1[0]).display, 'none');
        assert.equal(getComputedStyle(stamped1[1]).display, 'none');
        assert.equal(getComputedStyle(stamped1[2]).display, 'none');
        assert.equal(getComputedStyle(stamped1[3]).display, 'none');
        assert.equal(getComputedStyle(stamped1[4]).display, 'none');

        // Add one while hidden
        primitive.push('items', 'new 1');
        primitive.$.repeater1.render();
        stamped1 = Polymer.dom(primitive.$.container1).querySelectorAll('*:not(template)');
        assert.equal(getComputedStyle(stamped1[0]).display, 'none');
        assert.equal(getComputedStyle(stamped1[1]).display, 'none');
        assert.equal(getComputedStyle(stamped1[2]).display, 'none');
        assert.equal(getComputedStyle(stamped1[3]).display, 'none');
        assert.equal(getComputedStyle(stamped1[4]).display, 'none');
        assert.equal(getComputedStyle(stamped1[5]).display, 'none');

        // Add one then unhide
        primitive.push('items', 'new 2');
        primitive.$.repeater1.__hideTemplateChildren__ = false;
        primitive.$.repeater1.render();
        stamped1 = Polymer.dom(primitive.$.container1).querySelectorAll('*:not(template)');
        assert.equal(getComputedStyle(stamped1[0]).display, 'block');
        assert.equal(getComputedStyle(stamped1[1]).display, 'block');
        assert.equal(getComputedStyle(stamped1[2]).display, 'block');
        assert.equal(getComputedStyle(stamped1[3]).display, 'block');
        assert.equal(getComputedStyle(stamped1[4]).display, 'block');
        assert.equal(getComputedStyle(stamped1[5]).display, 'block');
        assert.equal(getComputedStyle(stamped1[6]).display, 'block');

        // Revert
        primitive.splice('items', 5, 2);
        primitive.$.repeater1.render();
      });

    });


    suite('limit', function() {

      var checkItemOrder = function(stamped) {
        for (var i=0; i<stamped.length; i++) {
          assert.equal(parseInt(stamped[i].textContent), i);
        }
      };

      test('initial limit', function() {
        limited.items = limited.preppedItems;
        limited.$.repeater._limit = 2;
        limited.$.repeater.render();
        var stamped = Polymer.dom(limited.root).querySelectorAll('*:not(template)');
        assert.equal(stamped.length, 2);
        checkItemOrder(stamped);
      });

      test('change item paths in & out of limit', function() {
        var stamped = Polymer.dom(limited.root).querySelectorAll('*:not(template)');
        limited.outerProp = {prop: 'changed'};
        assert.equal(stamped[0].prop, 'changed');
        limited.set('items.0.prop', '0-changed');
        limited.set('items.3.prop', '3-changed');
        assert.equal(stamped[0].textContent, '0-changed');
        limited.set('outerProp.prop', 'changed again');
        assert.equal(stamped[0].prop, 'changed again');
      });

      test('increase limit', function() {
        // Increase limit
        limited.$.repeater._limit = 10;
        limited.$.repeater.render();
        var stamped = Polymer.dom(limited.root).querySelectorAll('*:not(template)');
        assert.equal(stamped.length, 10);
        checkItemOrder(stamped);
        assert.equal(stamped[3].prop, 'changed again');
        assert.equal(stamped[3].textContent, '3-changed');
        limited.set('items.0.prop', 0);
        limited.set('items.3.prop', 3);
        // Increase limit
        limited.$.repeater._limit = 20;
        limited.$.repeater.render();
        stamped = Polymer.dom(limited.root).querySelectorAll('*:not(template)');
        assert.equal(stamped.length, 20);
        checkItemOrder(stamped);
      });

      test('increase limit above items.length', function() {
        limited.$.repeater._limit = 30;
        limited.$.repeater.render();
        stamped = Polymer.dom(limited.root).querySelectorAll('*:not(template)');
        assert.equal(stamped.length, 20);
        checkItemOrder(stamped);
      });

      test('decrease limit', function() {
        // Decrease limit
        limited.$.repeater._limit = 15;
        limited.$.repeater.render();
        var stamped = Polymer.dom(limited.root).querySelectorAll('*:not(template)');
        assert.equal(stamped.length, 15);
        checkItemOrder(stamped);
        // Decrease limit
        limited.$.repeater._limit = 0;
        limited.$.repeater.render();
        stamped = Polymer.dom(limited.root).querySelectorAll('*:not(template)');
        assert.equal(stamped.length, 0);
      });

      test('negative limit', function() {
        limited.$.repeater._limit = -10;
        limited.$.repeater.render();
        stamped = Polymer.dom(limited.root).querySelectorAll('*:not(template)');
        assert.equal(stamped.length, 0);
      });

    });

    suite('limit with sort', function() {

      var checkItemOrder = function(stamped) {
        for (var i=0; i<stamped.length; i++) {
          assert.equal(stamped[i].textContent, 19 - i);
        }
      };

      test('initial limit', function() {
        limited.$.repeater._limit = 2;
        limited.$.repeater.sort = function(a, b) {
          return b.prop - a.prop;
        };
        limited.items = null;
        limited.$.repeater.render();
        limited.items = limited.preppedItems;
        limited.$.repeater.render();
        var stamped = Polymer.dom(limited.root).querySelectorAll('*:not(template)');
        assert.equal(stamped.length, 2);
        checkItemOrder(stamped);
      });

      test('increase limit', function() {
        // Increase limit
        limited.$.repeater._limit = 10;
        limited.$.repeater.render();
        var stamped = Polymer.dom(limited.root).querySelectorAll('*:not(template)');
        assert.equal(stamped.length, 10);
        checkItemOrder(stamped);
        // Increase limit
        limited.$.repeater._limit = 20;
        limited.$.repeater.render();
        stamped = Polymer.dom(limited.root).querySelectorAll('*:not(template)');
        assert.equal(stamped.length, 20);
        checkItemOrder(stamped);
      });

      test('increase limit above items.length', function() {
        limited.$.repeater._limit = 30;
        limited.$.repeater.render();
        stamped = Polymer.dom(limited.root).querySelectorAll('*:not(template)');
        assert.equal(stamped.length, 20);
        checkItemOrder(stamped);
      });

      test('decrease limit', function() {
        // Decrease limit
        limited.$.repeater._limit = 15;
        limited.$.repeater.render();
        var stamped = Polymer.dom(limited.root).querySelectorAll('*:not(template)');
        assert.equal(stamped.length, 15);
        checkItemOrder(stamped);
        // Decrease limit
        limited.$.repeater._limit = 0;
        limited.$.repeater.render();
        stamped = Polymer.dom(limited.root).querySelectorAll('*:not(template)');
        assert.equal(stamped.length, 0);
      });

      test('negative limit', function() {
        limited.$.repeater._limit = -10;
        limited.$.repeater.render();
        stamped = Polymer.dom(limited.root).querySelectorAll('*:not(template)');
        assert.equal(stamped.length, 0);
      });

    });

    suite('limit with filter', function() {

      var checkItemOrder = function(stamped) {
        for (var i=0; i<stamped.length; i++) {
          assert.equal(stamped[i].textContent, i * 2);
        }
      };

      test('initial limit', function() {
        var items = limited.items;
        limited.$.repeater._limit = 2;
        limited.$.repeater.sort = null;
        limited.$.repeater.filter = function(a) {
          return (a.prop % 2) === 0;
        };
        limited.items = null;
        limited.$.repeater.render();
        limited.items = items;
        limited.$.repeater.render();
        var stamped = Polymer.dom(limited.root).querySelectorAll('*:not(template)');
        assert.equal(stamped.length, 2);
        checkItemOrder(stamped);
      });

      test('increase limit', function() {
        // Increase limit
        limited.$.repeater._limit = 5;
        limited.$.repeater.render();
        var stamped = Polymer.dom(limited.root).querySelectorAll('*:not(template)');
        assert.equal(stamped.length, 5);
        checkItemOrder(stamped);
        // Increase limit
        limited.$.repeater._limit = 10;
        limited.$.repeater.render();
        stamped = Polymer.dom(limited.root).querySelectorAll('*:not(template)');
        assert.equal(stamped.length, 10);
        checkItemOrder(stamped);
      });

      test('increase limit above items.length', function() {
        limited.$.repeater._limit = 30;
        limited.$.repeater.render();
        stamped = Polymer.dom(limited.root).querySelectorAll('*:not(template)');
        assert.equal(stamped.length, 10);
          checkItemOrder(stamped);
      });

      test('decrease limit', function() {
        // Decrease limit
        limited.$.repeater._limit = 5;
        limited.$.repeater.render();
        var stamped = Polymer.dom(limited.root).querySelectorAll('*:not(template)');
        assert.equal(stamped.length, 5);
        checkItemOrder(stamped);
        // Decrease limit
        limited.$.repeater._limit = 0;
        limited.$.repeater.render();
        stamped = Polymer.dom(limited.root).querySelectorAll('*:not(template)');
        assert.equal(stamped.length, 0);
      });

      test('negative limit', function() {
        limited.$.repeater._limit = -10;
        limited.$.repeater.render();
        stamped = Polymer.dom(limited.root).querySelectorAll('*:not(template)');
        assert.equal(stamped.length, 0);
      });

    });

    suite('limit with sort & filter', function() {

      var checkItemOrder = function(stamped) {
        for (var i=0; i<stamped.length; i++) {
          assert.equal(stamped[i].textContent, (9 - i) * 2);
        }
      };

      test('initial limit', function() {
        var items = limited.items;
        limited.$.repeater._limit = 2;
        limited.$.repeater.sort = function(a, b) {
          return b.prop - a.prop;
        };
        limited.$.repeater.filter = function(a) {
          return (a.prop % 2) === 0;
        };
        limited.items = null;
        limited.$.repeater.render();
        limited.items = items;
        limited.$.repeater.render();
        var stamped = Polymer.dom(limited.root).querySelectorAll('*:not(template)');
        assert.equal(stamped.length, 2);
        checkItemOrder(stamped);
      });

      test('increase limit', function() {
        // Increase limit
        limited.$.repeater._limit = 5;
        limited.$.repeater.render();
        var stamped = Polymer.dom(limited.root).querySelectorAll('*:not(template)');
        assert.equal(stamped.length, 5);
        checkItemOrder(stamped);
        // Increase limit
        limited.$.repeater._limit = 10;
        limited.$.repeater.render();
        stamped = Polymer.dom(limited.root).querySelectorAll('*:not(template)');
        assert.equal(stamped.length, 10);
        checkItemOrder(stamped);
      });

      test('increase limit above items.length', function() {
        limited.$.repeater._limit = 30;
        limited.$.repeater.render();
        stamped = Polymer.dom(limited.root).querySelectorAll('*:not(template)');
        assert.equal(stamped.length, 10);
        checkItemOrder(stamped);
      });

      test('decrease limit', function() {
        // Decrease limit
        limited.$.repeater._limit = 5;
        limited.$.repeater.render();
        var stamped = Polymer.dom(limited.root).querySelectorAll('*:not(template)');
        assert.equal(stamped.length, 5);
        checkItemOrder(stamped);
        // Decrease limit
        limited.$.repeater._limit = 0;
        limited.$.repeater.render();
        stamped = Polymer.dom(limited.root).querySelectorAll('*:not(template)');
        assert.equal(stamped.length, 0);
      });

      test('negative limit', function() {
        limited.$.repeater._limit = -10;
        limited.$.repeater.render();
        stamped = Polymer.dom(limited.root).querySelectorAll('*:not(template)');
        assert.equal(stamped.length, 0);
      });

    });

    // TODO(kschaaf): This test suite has proven to be flaky only on IE, only
    // on CI (Sauce) presumably because of rAF handling in the CI environment
    // disabling for IE for now to avoid Polymer tests being flaky
    if (!/Trident/.test(navigator.userAgent)) {

      suite('chunked rendering', function() {

        test('basic chunked rendering', function(done) {

          var checkItemOrder = function(stamped) {
            for (var i=0; i<stamped.length; i++) {
              assert.equal(stamped[i].textContent, i);
            }
          };

          var lastLength = 0;
          var checkCount = function() {
            var stamped = Polymer.dom(chunked.root).querySelectorAll('*:not(template)');
            checkItemOrder(stamped);
            if (stamped.length && lastLength === 0) {
              // Initial rendering of initial count
              assert.equal(stamped.length, 10);
            } else {
              // Remaining rendering incremenets
              assert.isTrue(stamped.length > lastLength);
            }
            if (stamped.length < 100) {
              lastLength = stamped.length;
              checkUntilComplete();
            } else {
              // Final rendering at exact item count
              assert.equal(stamped.length, 100);
              done();
            }
          };
          var checkUntilComplete = function() {
            // On polyfilled MO, need to wait one setTimeout before rAF
            if (MutationObserver._isPolyfilled) {
              setTimeout(function() {
                requestAnimationFrame(checkCount);
              });
            } else {
              requestAnimationFrame(checkCount);
            }
          };

          chunked.items = chunked.preppedItems.slice();
          checkUntilComplete();

        });

        test('mutations during chunked rendering', function(done) {

          var checkItemOrder = function(stamped) {
            var last = -1;
            for (var i=0; i<stamped.length; i++) {
              var curr = parseFloat(stamped[i].textContent);
              assert.isTrue(curr > last);
              last = curr;
            }
          };

          var mutateArray = function(repeater, renderedCount) {
            // The goal here is to remove & add some, and do it over
            // the threshold of where we have currently rendered items, and
            // ensure that the prop values of the newly inserted items are in
            // ascending order so we can do a simple check in checkItemOrder
            var overlap = 2;
            var remove = 4;
            var add = 6;
            var start = renderedCount.length - overlap;
            if (start + add < repeater.items.length) {
              var end = start + remove;
              var args = ['items', start, remove];
              var startVal = repeater.items[start].prop;
              var endVal = repeater.items[end].prop;
              var delta = (endVal - startVal) / add;
              for (var i=0; i<add; i++) {
                args.push({prop: startVal + i*delta});
              }
              repeater.splice.apply(repeater, args);
            }
          };

          var lastLength = 0;
          var mutateCount = 5;
          var checkCount = function() {
            var stamped = Polymer.dom(chunked.root).querySelectorAll('*:not(template)');
            checkItemOrder(stamped);
            if (stamped.length && lastLength === 0) {
              // Initial rendering of initial count
              assert.equal(stamped.length, 10);
            } else {
              // Remaining rendering incremenets
              assert.isTrue(stamped.length > lastLength);
            }
            if (stamped.length < chunked.items.length) {
              if (mutateCount-- > 0) {
                mutateArray(chunked, stamped);
              }
              lastLength = stamped.length;
              checkUntilComplete();
            } else {
              // Final rendering at exact item count
              assert.equal(stamped.length, chunked.items.length);
              done();
            }
          };
          var checkUntilComplete = function() {
            // On polyfilled MO, need to wait one setTimeout before rAF
            if (MutationObserver._isPolyfilled) {
              setTimeout(function() {
                requestAnimationFrame(checkCount);
              });
            } else {
              requestAnimationFrame(checkCount);
            }
          };

          chunked.items = chunked.preppedItems.slice();
          checkUntilComplete();

        });


        test('mutations during chunked rendering, sort & filtered', function(done) {

          var checkItemOrder = function(stamped) {
            var last = Infinity;
            for (var i=0; i<stamped.length; i++) {
              var curr = parseFloat(stamped[i].textContent);
              assert.isTrue(curr <= last);
              assert.strictEqual(curr % 2, 0);
              last = curr;
            }
          };

          var mutateArray = function(repeater, stamped) {
            var start = parseInt(stamped[0].textContent);
            var end = parseInt(stamped[stamped.length-1].textContent);
            var mid = (end-start)/2;
            for (var i=0; i<5; i++) {
              chunked.push('items', {prop: mid + 1});
            }
            chunked.splice('items', Math.round(stamped.length/2), 3);
          };

          var lastLength = 0;
          var mutateCount = 5;
          var checkCount = function() {
            var stamped = Polymer.dom(chunked.root).querySelectorAll('*:not(template)');
            checkItemOrder(stamped);
            var filteredLength = chunked.items.filter(chunked.$.repeater.filter).length;
            if (stamped.length && lastLength === 0) {
              // Initial rendering of initial count
              assert.equal(stamped.length, 10);
            } else {
              // Remaining rendering incremenets
              if (stamped.length < filteredLength) {
                assert.isTrue(stamped.length > lastLength);
              }
            }
            if (stamped.length < filteredLength) {
              if (mutateCount-- > 0) {
                mutateArray(chunked, stamped);
              }
              lastLength = stamped.length;
              checkUntilComplete();
            } else {
              assert.equal(stamped.length, filteredLength);
              done();
            }
          };
          var checkUntilComplete = function() {
            // On polyfilled MO, need to wait one setTimeout before rAF
            if (MutationObserver._isPolyfilled) {
              setTimeout(function() {
                requestAnimationFrame(checkCount);
              });
            } else {
              requestAnimationFrame(checkCount);
            }
          };

          chunked.$.repeater.sort = function(a, b) {
            return b.prop - a.prop;
          };
          chunked.$.repeater.filter = function(a) {
            return (a.prop % 2) === 0;
          };
          chunked.items = chunked.preppedItems.slice();
          checkUntilComplete();

        });

      });

      suite('notification suppression', function() {

        test('re-enable dom-change', function() {
          if (Polymer.Settings.suppressTemplateNotifications) {
            unconfigured1.$.repeater.setAttribute('notify-dom-change', '');
            unconfigured1.domUpdateHandlerCount = 0;
            unconfigured.items = unconfigured.items.slice();
            setTimeout(function() {
              assert.equal(unconfigured1.domUpdateHandlerCount, 1);
            });
          }
        });

      });

    }

  </script>

</body>
</html>
